package cluster

import (
	"context"
	"errors"

	"gorm.io/gorm"

	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/constant"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/apimiddleware/bizerror"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (c *serverImpl) DeleteCluster(
	ctx context.Context,
	request *tidbmgmtservicev1.DeleteClusterRequest,
) (*tidbmgmtservicev1.Cluster, error) {
	if request == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "request is nil")
	}

	if request.ClusterId == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster id is invalid")
	}

	var (
		cluster *entity.Cluster
		err     error
	)

	switch request.DeployType {
	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_SERVERLESS:
		cluster, err = c.serverlessClusterSvc.GetCluster(
			ctx,
			request.GetClusterId(),
			entity.ClusterViewClusterViewLocal,
		)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "serverless cluster not found")
			}
			return nil, bizerror.NewInternal(err, "failed to get serverless cluster")
		}
	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_DEDICATED:
		cluster, err = c.dedicatedClusterSvc.GetCluster(
			ctx,
			request.GetClusterId(),
			entity.ClusterViewClusterViewLocal,
			false,
			false,
		)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "dedicated cluster not found")
			}
			return nil, bizerror.NewInternal(err, "failed to get dedicated cluster")
		}
	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_NEXTGEN:
		cluster, err = c.nextgenClusterSvc.GetCluster(
			ctx,
			request.GetClusterId(),
			entity.ClusterViewClusterViewLocal,
			false,
		)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "nextgen cluster not found")
			}
			return nil, bizerror.NewInternal(err, "failed to get nextgen cluster")
		}
	}

	// gen request meta and append to outgoing meta
	ctx = metadata.AppendToOutgoingMeta(ctx, &metadata.RequestMeta{
		OrgID:            cluster.OrganizationId,
		DefaultProjectID: cluster.ProjectId,
		ValidProjectList: []uint64{cluster.ProjectId},
		ClusterID:        request.ClusterId,
		UserID:           "0",
	})

	switch request.DeployType {
	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_SERVERLESS:
		cluster, customStatus, err := c.serverlessClusterSvc.DeleteCluster(ctx, request.ClusterId)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "cluster not found")
			} else if errors.Is(err, constant.ErrClusterCustomStatusForbidden) {
				return nil, bizerror.NewForbiddenForClusterCustomStatus(err, customStatus.StatusType.String())
			}
			return nil, bizerror.NewInternal(err, "failed to delete cluster record")
		}
		return cvtToMgmtCluster(cluster, nil), nil

	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_DEDICATED:
		cluster, customStatus, err := c.dedicatedClusterSvc.DeleteCluster(ctx, request.ClusterId, false, false)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "cluster not found")
			} else if errors.Is(err, constant.ErrClusterCustomStatusForbidden) {
				return nil, bizerror.NewForbiddenForClusterCustomStatus(err, customStatus.StatusType.String())
			}
			return nil, bizerror.NewInternal(err, "failed to delete cluster record")
		}
		return cvtToMgmtCluster(cluster, nil), nil
	case tidbmgmtservicev1.DeployType_DEPLOY_TYPE_NEXTGEN:
		cluster, customStatus, err := c.nextgenClusterSvc.DeleteCluster(ctx, request.ClusterId, false)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, bizerror.NewNotFound(err, "cluster not found")
			} else if errors.Is(err, constant.ErrClusterCustomStatusForbidden) {
				return nil, bizerror.NewForbiddenForClusterCustomStatus(err, customStatus.StatusType.String())
			}
			return nil, bizerror.NewInternal(err, "failed to delete cluster record")
		}
		return cvtToMgmtCluster(cluster, nil), nil
	}

	return nil, bizerr.New(bizerr.ErrCodeParams, "invalid deploy type")
}
