package tenant

import (
	"context"
	"strconv"
	"time"

	"github.com/pingcap/dbaas/central/config"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/grpc/grpcli"
	"github.com/pingcap/dbaas/central/utils"
	"github.com/tidbcloud/idl/pbgen/proto/central"
	"github.com/tidbcloud/idl/pbgen/proto/core"
)

func (s *tenantService) GetTiDBCloudDelegationInfo(ctx context.Context, req *central.GetTiDBCloudDelegationInfoReq) (*central.GetTiDBCloudDelegationInfoResp, error) {
	orgID := entity.ID(req.OrgId)
	projectID := entity.ID(req.ProjectId)
	userContext := s.userContext(ctx)

	err := userContext.CheckOrgIDAndProjectID(orgID, projectID)
	if err != nil {
		return nil, err
	}

	accountID := config.Global().AwsConfig.AccountID
	// FIXME(chenfei): compatibility, get external_id from network infra API
	// use project ID as external ID
	externalID := strconv.FormatUint(projectID.Uint64(), 10)

	return &central.GetTiDBCloudDelegationInfoResp{
		AccountId:  accountID,
		ExternalId: externalID,
		BaseResp:   &central.BaseResp{},
	}, nil
}

func (s *tenantService) CreateCrossAccountDeployment(ctx context.Context, req *central.CreateCrossAccountDeploymentReq) (*central.CreateCrossAccountDeploymentResp, error) {
	orgID := entity.ID(req.OrgId)
	projectID := entity.ID(req.ProjectId)
	userContext := s.userContext(ctx)

	err := userContext.CheckOrgIDAndProjectID(orgID, projectID)
	if err != nil {
		return nil, err
	}

	createDeploymentReq := &core.CreateXAccountDeployReq{
		ProjectId:     projectID.Uint64(),
		CloudProvider: req.Provider,
		Region:        req.Region,
		Aws: &core.AwsXAccountDeployParams{
			VpcId:                   req.VpcId,
			SecurityGroupId:         req.SecurityGroupId,
			SubnetIds:               req.SubnetIds,
			BucketName:              req.BucketName,
			KmsKeyArn:               req.KmsKeyArn,
			PcaClusterComponentsArn: req.PcaArnClusterComponents,
			PcaClientArn:            req.PcaArnClient,
			NodeRoleArn:             req.RoleArnNode,
			EksRoleArn:              req.RoleArnEks,
			TidbServiceRoleArn:      req.RoleArnTidbCloud,
		},
		BaseReq: nil,
	}
	createDeploymentResp, err := grpcli.CreateCrossAccountDeployment(ctx, createDeploymentReq)
	if err != nil {
		return nil, err
	}

	resp := &central.CreateCrossAccountDeploymentResp{
		BaseResp: &central.BaseResp{},
		Id:       createDeploymentResp.XaccountDeployId,
	}
	return resp, nil
}

func (s *tenantService) ListCrossAccountDeployments(ctx context.Context, req *central.ListCrossAccountDeploymentsReq) (*central.ListCrossAccountDeploymentResp, error) {
	orgID := entity.ID(req.OrgId)
	projectID := entity.ID(req.ProjectId)
	userContext := s.userContext(ctx)

	err := userContext.CheckOrgIDAndProjectID(orgID, projectID)
	if err != nil {
		return nil, err
	}

	listXAccountDeployReq := &core.ListXAccountDeployReq{
		Filter: &core.XAccountDeployFilter{
			ProjectIds: []uint64{projectID.Uint64()},
		},
		BaseReq: nil,
	}
	listXAccountDeployResp, err := grpcli.ListCrossAccountDeployments(ctx, listXAccountDeployReq)
	if err != nil {
		return nil, err
	}
	deployments := buildCrossAccountDeployments(listXAccountDeployResp.XaccountDeploys)

	resp := &central.ListCrossAccountDeploymentResp{
		Items:    deployments,
		Total:    int32(len(deployments)),
		BaseResp: &central.BaseResp{},
	}
	return resp, nil
}

func buildCrossAccountDeployments(deployments []*core.XAccountDeploy) []*central.CrossAccountDeployment {
	items := make([]*central.CrossAccountDeployment, 0, len(deployments))
	for _, deploy := range deployments {
		createdAt := time.Unix(deploy.CreatedAt, 0)

		deployment := &central.CrossAccountDeployment{
			Id:                      deploy.Id,
			CreatedAt:               utils.MustTimestampProto(createdAt),
			ProjectId:               deploy.ProjectId,
			Provider:                deploy.CloudProvider,
			Region:                  deploy.Region,
			VpcId:                   "",
			SecurityGroupId:         "",
			SubnetIds:               nil,
			BucketName:              "",
			KmsKeyArn:               "",
			PcaArnClusterComponents: "",
			PcaArnClient:            "",
			RoleArnTidbCloud:        "",
			RoleArnEks:              "",
			RoleArnNode:             "",
			Status:                  deploy.Status.String(),
		}

		awsParams := deploy.Aws
		if awsParams != nil {
			deployment.VpcId = awsParams.VpcId
			deployment.SecurityGroupId = awsParams.SecurityGroupId
			deployment.SubnetIds = awsParams.SubnetIds
			deployment.BucketName = awsParams.BucketName
			deployment.KmsKeyArn = awsParams.KmsKeyArn
			deployment.PcaArnClusterComponents = awsParams.PcaClusterComponentsArn
			deployment.PcaArnClient = awsParams.PcaClientArn
			deployment.RoleArnTidbCloud = awsParams.TidbServiceRoleArn
			deployment.RoleArnEks = awsParams.EksRoleArn
			deployment.RoleArnNode = awsParams.NodeRoleArn
		}

		items = append(items, deployment)
	}

	return items
}

func (s *tenantService) DeleteCrossAccountDeployment(ctx context.Context, req *central.DeleteCrossAccountDeploymentReq) (*central.DefaultResp, error) {
	orgID := entity.ID(req.OrgId)
	projectID := entity.ID(req.ProjectId)
	userContext := s.userContext(ctx)

	err := userContext.CheckOrgIDAndProjectID(orgID, projectID)
	if err != nil {
		return nil, err
	}

	deleteXAccountDeployReq := &core.DeleteXAccountDeployReq{
		XaccountDeployId: req.Id,
		BaseReq:          nil,
	}
	_, err = grpcli.DeleteCrossAccountDeployment(ctx, deleteXAccountDeployReq)
	if err != nil {
		return nil, err
	}
	resp := &central.DefaultResp{
		BaseResp: &central.BaseResp{},
	}
	return resp, nil
}
