package dataflow

import (
	"encoding/json"

	httptransport "github.com/go-openapi/runtime/client"
	"github.com/go-openapi/strfmt"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"

	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/dataflow/client"
	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/dataflow/client/backup_service"
	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/dataflow/model"
)

type Cli struct {
	*client.GRPCForOurDBaaSDataflowService

	su *suite.Suite
}

func NewClient(su *suite.Suite, host, bearerToken string) (*Cli, error) {
	trans := httptransport.New(host, "", []string{"https"})
	trans.DefaultAuthentication = httptransport.BearerToken(bearerToken)
	return &Cli{su: su, GRPCForOurDBaaSDataflowService: client.New(trans, strfmt.Default)}, nil
}

func (cli *Cli) GetDedicatedBackupSettings(orgId, projectId, clusterId string) *model.DataflowBackupSettingResp {
	params := backup_service.NewGetBackupSettingParams()
	params.OrgID = orgId
	params.ProjectID = projectId
	params.ClusterID = clusterId

	resp, err := cli.BackupService.GetBackupSetting(params, nil)
	require.NoError(cli.su.T(), err)
	return resp.Payload
}

func (cli *Cli) GetServerlessBackupSettings(orgId, projectId, clusterId string) *model.DataflowAutoBackupSetting {
	params := backup_service.NewGetAutoBackupSettingParams()
	params.OrgID = orgId
	params.ProjectID = projectId
	params.ClusterID = clusterId

	resp, err := cli.BackupService.GetAutoBackupSetting(params, nil)
	require.NoError(cli.su.T(), err)
	return resp.Payload
}

func (cli *Cli) DeleteBackup(orgId, projectId, clusterId, backupId string) {
	params := backup_service.NewDeleteBackupParams()
	params.OrgID = orgId
	params.ProjectID = projectId
	params.ClusterID = clusterId
	params.ID = backupId

	_, err := cli.BackupService.DeleteBackup(params, nil)
	require.NoError(cli.su.T(), err)
}

func (cli *Cli) RestoreBackup(
	orgId, projectId, clusterId, backupId, clusterName, region string,
) *model.DataflowRestoreResp {
	params := backup_service.NewRestoreBackupParams()
	params.OrgID = orgId
	params.ProjectID = projectId
	params.ClusterID = clusterId
	params.ID = backupId
	params.SetBody(backup_service.RestoreBackupBody{
		BackupRegion: region,
		ClusterName:  clusterName,
		Components: []*model.DataflowSimpleClusterComponent{
			{
				ComponentType:   lo.ToPtr(model.DataflowComponentTypeCOMPONENTTYPETIDB),
				NodeProfileName: lo.ToPtr("4C16G"),
				Replicas:        lo.ToPtr(int32(1)),
				StorageSizeGi:   nil,
			},
			{
				ComponentType:   lo.ToPtr(model.DataflowComponentTypeCOMPONENTTYPETIKV),
				NodeProfileName: lo.ToPtr("4C16G"),
				Replicas:        lo.ToPtr(int32(3)),
				StorageSizeGi:   lo.ToPtr(int32(200)),
			},
		},
		Description: "", // leave it empty
		Password:    "", // leave it empty
		Port:        4000,
		Region:      region,
		RestoreMode: lo.ToPtr(model.DataflowRestoreModeRESTOREMODESNAPSHOT),
		RestoredTs:  "", // leave it empty
	})

	resp, err := cli.BackupService.RestoreBackup(params, nil)
	require.NoError(cli.su.T(), err)
	require.NotEmptyf(cli.su.T(), resp.Payload, "invalid response: %s", cli.RespJson(resp))
	require.Falsef(
		cli.su.T(),
		resp.Payload.BaseResp != nil && resp.Payload.BaseResp.ErrCode != "0",
		"invalid response: %s",
		cli.RespJson(resp),
	)

	return resp.Payload
}

func (cli *Cli) RespJson(resp any) string {
	b, err := json.Marshal(resp)
	require.NoErrorf(cli.su.T(), err, "marshal error: %s", err)
	return string(b)
}

func (cli *Cli) CreateBackupSchedule(
	orgId, projectId, clusterId, backupName, backupTime string,
) (*backup_service.CreateBackupScheduleOK, error) {
	params := backup_service.NewCreateBackupScheduleParams()
	params.OrgID = orgId
	params.ProjectID = projectId
	params.ClusterID = clusterId
	params.SetBody(backup_service.CreateBackupScheduleBody{
		BackupMode:      model.DataflowBackupModeFULL.Pointer(),
		BackupTime:      lo.ToPtr(backupTime),
		BackupType:      model.DataflowBackupTypeMANUAL.Pointer(),
		Description:     nil, // leave it empty
		Name:            lo.ToPtr(backupName),
		RetentionPeriod: 0, // leave it empty
	})

	return cli.BackupService.CreateBackupSchedule(params, nil)
}
