package action

import (
	"context"
	"strconv"

	regionaldedicatedv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	clusterrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cluster"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/tidbgroup"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/gkeheterogeneous"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func newGKEGatekeeperTarget(
	ctx context.Context,
	clusterRepo clusterrepo.Repo,
	regionRepo region.Repo,
	tidbGroupRepo tidbgroup.Repo,
	req *globaldedicatedv1.ApplyGKEHeterogeneousDeployRequest,
) (*gkeGatekeeperTarget, bizerr.BizError) {
	regionEn, err := prepareGKEHeterogeneousApplyTarget(ctx, clusterRepo, regionRepo, req)
	if err != nil {
		return nil, err
	}
	componentType, err := gkeheterogeneous.ToRegionalComponentTypeOrError(req.GetComponentType())
	if err != nil {
		return nil, err
	}
	tidbGroupKind, err := gkeGatekeeperTiDBGroupKind(ctx, tidbGroupRepo, req)
	if err != nil {
		return nil, err
	}
	return &gkeGatekeeperTarget{
		region:        regionEn,
		clusterID:     strconv.FormatUint(req.GetClusterId(), 10),
		componentType: componentType,
		tidbGroupID:   formatOptionalUint64(req.GetTidbGroupId()),
		tidbGroupKind: tidbGroupKind,
	}, nil
}

func gkeGatekeeperTiDBGroupKind(
	ctx context.Context,
	tidbGroupRepo tidbgroup.Repo,
	req *globaldedicatedv1.ApplyGKEHeterogeneousDeployRequest,
) (regionaldedicatedv1.TiDBGroupKind, bizerr.BizError) {
	if req.GetComponentType() != globaldedicatedv1.ComponentType_TIDB {
		return regionaldedicatedv1.TiDBGroupKind_TIDB_GROUP_KIND_UNSPECIFIED, nil
	}
	if req.GetTidbGroupId() == 0 {
		return regionaldedicatedv1.TiDBGroupKind_TIDB_GROUP_KIND_UNSPECIFIED,
			bizerr.New(bizerr.ErrCodeParams, "tidb_group_id is required for tidb heterogeneous deploy")
	}
	group, err := tidbGroupRepo.Load(ctx, req.GetClusterId(), req.GetTidbGroupId())
	if err != nil {
		return regionaldedicatedv1.TiDBGroupKind_TIDB_GROUP_KIND_UNSPECIFIED, err
	}
	if group.Default {
		return regionaldedicatedv1.TiDBGroupKind_TIDB_GROUP_KIND_DEFAULT, nil
	}
	return regionaldedicatedv1.TiDBGroupKind_TIDB_GROUP_KIND_EXTRA, nil
}

func isGKEHeterogeneousDeployReadyForGatekeeper(status regionaldedicatedv1.GKEHeterogeneousDeployStatus) bool {
	return status == regionaldedicatedv1.GKEHeterogeneousDeployStatus_GKE_HETEROGENEOUS_DEPLOY_STATUS_READY_FOR_GATEKEEPER ||
		status == regionaldedicatedv1.GKEHeterogeneousDeployStatus_GKE_HETEROGENEOUS_DEPLOY_STATUS_HETEROGENEOUS_READY
}

func checkGKEHeterogeneousDeployReadyForGatekeeper(deploy *regionaldedicatedv1.GKEHeterogeneousDeploy) bizerr.BizError {
	if deploy == nil {
		return bizerr.New(bizerr.ErrCodeRegionalAPI, "empty gke heterogeneous deploy response from regional-server")
	}
	if isGKEHeterogeneousDeployReadyForGatekeeper(deploy.GetStatus()) {
		return nil
	}
	return bizerr.New(
		bizerr.ErrCodeUnknown,
		"gke heterogeneous deploy is not ready for gatekeeper; status=%s",
		deploy.GetStatus().String(),
	)
}

func formatOptionalUint64(value uint64) string {
	if value == 0 {
		return ""
	}
	return strconv.FormatUint(value, 10)
}
