package action

import (
	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/fastflow/pkg/entity/run"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	exportrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/export"
	regionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	CancelExportAction = "cancel_export"
)

type CancelExportActionStruct struct {
	exportRepo        exportrepo.ExportRepo
	regionRepo        regionrepo.Repo
	regionalserverCli regionalserver.Client
}

func NewCancelExportAction(
	exportRepo exportrepo.ExportRepo,
	regionRepo regionrepo.Repo,
	regionalserverCli regionalserver.Client,
) *CancelExportActionStruct {
	return &CancelExportActionStruct{
		exportRepo:        exportRepo,
		regionRepo:        regionRepo,
		regionalserverCli: regionalserverCli,
	}
}

func (a *CancelExportActionStruct) Name() string {
	return CancelExportAction
}

func (a *CancelExportActionStruct) ParameterNew() any {
	return &common.ExportParameter{}
}

func (a *CancelExportActionStruct) Run(ctx run.ExecuteContext, params any) error {
	cctx, span := workflow.GenerateContext(ctx)
	defer span.End()

	clusterId, exportId, err1 := common.GetExportParams(params)
	if err1 != nil {
		tilog.Error(cctx, "cancel export action: invalid params", zap.Error(err1))
		return err1
	}

	tilog.Info(cctx, "cancel export action start", zap.String("cluster_id", clusterId), zap.String("export_id", exportId))

	ent, err := a.exportRepo.GetByClusterAndExportId(cctx, clusterId, exportId)
	if err != nil {
		tilog.Error(cctx, "cancel export action: failed to get export", zap.Error(err), zap.String("export_id", exportId))
		return err
	}

	if ent.State != schema.ExportStateCanceled {
		tilog.Error(
			cctx,
			"cancel export action: export not in cancel state",
			zap.String("export_id", exportId),
			zap.String("state", string(ent.State)),
		)
		return bizerr.New(bizerr.ErrCodeParams, "export not in cancel state")
	}

	region, err := a.regionRepo.Get(cctx, ent.RegionId)
	if err != nil {
		tilog.Error(cctx, "cancel export action: failed to get region", zap.Error(err), zap.Uint64("region_id", ent.RegionId))
		return err
	}

	err = a.regionalserverCli.CancelExport(cctx, region, &clusterngv1beta.CancelExportRequest{
		ClusterId: clusterId,
		ExportId:  exportId,
	})
	if err != nil {
		if err.ErrCode() != bizerr.ErrCodeRecordNotFound {
			tilog.Error(cctx, "regional cancel export failed", zap.Error(err), zap.String("export_id", exportId))
			return err
		}
		tilog.Info(cctx, "cancel export action skip: export not found", zap.String("export_id", exportId))
	}

	tilog.Info(cctx, "cancel export action done", zap.String("export_id", exportId))
	deleteExportRunningMetric(ent)
	return nil
}
