package privatelink

import (
	"context"
	"strconv"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/privatelink"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/resourcepoolpolicy"
	servicecommon "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/common"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

func (s *service) DeletePrivateLinkService(
	ctx context.Context,
	req *globalngv1.DeletePrivateLinkServiceRequest,
) bizerr.BizError {
	ctx, span := tracer.Start(ctx, "Domain.DeletePrivateLinkServiceSvc")
	defer span.End()

	if req.ClusterId == 0 {
		return bizerr.New(bizerr.ErrCodeParams, "cluster_id is required")
	}
	if req.TidbGroupId == 0 {
		return bizerr.New(bizerr.ErrCodeParams, "tidb_group_id is required")
	}

	cluster, err := s.clusterRepo.Get(ctx, req.ClusterId, false)
	if err != nil {
		return bizerr.WrapError(err, "get cluster failed")
	}
	if berr := servicecommon.CheckClusterResourcePoolLifecycle(
		ctx, s.resourcePoolRepo, cluster, resourcepoolpolicy.OperationUpdateNetwork,
	); berr != nil {
		return berr
	}

	if cluster.State != globalngv1.Cluster_AVAILABLE {
		return bizerr.New(bizerr.ErrCodeParams, "cluster is not available")
	}

	_, err = s.tidbGroupRepo.Load(ctx, req.ClusterId, req.TidbGroupId)
	if err != nil {
		return bizerr.WrapError(err, "get tidb group failed")
	}

	services, err := s.privatelinkRepo.ListPrivateLinkServices(ctx, &privatelink.Filter{
		ClusterID:   req.ClusterId,
		TidbGroupID: req.TidbGroupId,
	})
	if err != nil {
		return bizerr.WrapError(err, "list private link services failed")
	}
	if len(services) == 0 {
		return nil
	}

	terr := s.transaction.Transaction(ctx, func(ctx context.Context) error {
		if berr := servicecommon.LockClusterResourcePoolLifecycle(
			ctx, s.resourcePoolRepo, cluster, resourcepoolpolicy.OperationUpdateNetwork,
		); berr != nil {
			return berr
		}
		for _, svc := range services {
			if err := s.privatelinkRepo.DeletePrivateLinkConnectionByServiceID(ctx, svc.PrivateLinkServiceID); err != nil {
				return err
			}
			if err := s.privatelinkRepo.DeletePrivateLinkService(ctx, svc.PrivateLinkServiceID); err != nil {
				return err
			}
		}

		workflowErr := s.flow.RunDagWithBizId(
			ctx,
			common.DeletePrivateLinkService,
			strconv.FormatUint(cluster.OrganizationId, 10),
			"0",
			strconv.FormatUint(cluster.ClusterId, 10),
			map[string]string{
				workflow.KeyTraceId:                            workflow.GetTraceId(ctx),
				common.KeyClusterId:                            strconv.FormatUint(cluster.ClusterId, 10),
				common.KeyTidbGroupIdWithPrivateLinkServiceIds: common.GenerateTidbGroupIdWithPrivateLinkServiceIds(services),
			},
		)
		if workflowErr != nil {
			return bizerr.WrapErrorWithCode(workflowErr, bizerr.ErrCodeUnknown, "create async workflow failed")
		}

		return nil
	})
	if terr != nil {
		return bizerr.WrapError(terr, "delete private link service failed")
	}

	return nil
}
