package action

import (
	"fmt"
	"strconv"

	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"
	clusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	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"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/resourcepoolpolicy"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/export"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	CreateExportAction = "create_export"
)

type CreateExportActionStruct struct {
	exportRepo        exportrepo.ExportRepo
	clusterRepo       clusterrepo.Repo
	resourcePoolRepo  resourcepoolrepo.Repo
	regionRepo        regionrepo.Repo
	regionalserverCli regionalserver.Client
}

func NewCreateExportAction(
	exportRepo exportrepo.ExportRepo,
	clusterRepo clusterrepo.Repo,
	resourcePoolRepo resourcepoolrepo.Repo,
	regionRepo regionrepo.Repo,
	regionalserverCli regionalserver.Client,
) *CreateExportActionStruct {
	return &CreateExportActionStruct{
		exportRepo:        exportRepo,
		clusterRepo:       clusterRepo,
		resourcePoolRepo:  resourcePoolRepo,
		regionRepo:        regionRepo,
		regionalserverCli: regionalserverCli,
	}
}

func (a *CreateExportActionStruct) Name() string {
	return CreateExportAction
}

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

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

	clusterId, exportId, err := common.GetExportParams(params)
	if err != nil {
		tilog.Error(cctx, "create export action: invalid params", zap.Error(err))
		return err
	}
	clusterID, err := strconv.ParseUint(clusterId, 10, 64)
	if err != nil {
		err = fmt.Errorf("parse cluster id: %w", err)
		tilog.Error(cctx, "create export action: invalid cluster id", zap.Error(err), zap.String("cluster_id", clusterId))
		return err
	}

	tilog.Info(cctx, "create 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, "create export action: failed to get export", zap.Error(err), zap.String("export_id", exportId))
		return err
	}

	regionalExport := export.SchemaExportToRegionalExport(ent.Export)

	region, err := a.regionRepo.Get(cctx, ent.RegionId)
	if err != nil {
		tilog.Error(cctx, "create export action: get region failed", zap.Error(err))
		return err
	}
	stop, err := guardClusterResourcePoolMutationByID(
		cctx,
		a.clusterRepo,
		a.resourcePoolRepo,
		clusterID,
		resourcepoolpolicy.OperationImportExport,
	)
	if err != nil {
		tilog.Error(cctx, "create export action: resource pool lifecycle guard failed", zap.Error(err), zap.String("cluster_id", clusterId))
		return err
	}
	if stop {
		return nil
	}

	_, err = a.regionalserverCli.CreateExport(cctx, region, &clusterngv1beta.CreateExportRequest{
		ClusterId: ent.ClusterId,
		Export:    regionalExport,
	})
	if err != nil {
		tilog.Error(cctx, "create export request to regional failed", zap.Error(err), zap.String("export_id", exportId))
		return err
	}

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