package cmek

import (
	"context"
	"strconv"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapicommonv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/common/v1beta1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	appcommon "github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/app/openapi/nextgen/common"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/enum"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (s serverImpl) GetCmekAccessIamPrincipal(ctx context.Context,
	request *openapingv1beta2.GetCmekAccessIamPrincipalRequest,
) (*openapingv1beta2.CmekAccessIamPrincipal, error) {
	ctx, span := tracer.Start(ctx, "GetCmekAccessIamPrincipal")
	defer span.End()

	reqMeta, err := metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	provider, region, err := common.ParseOpenApiRegionNameOrId(request.GetRegionId())
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region, please check and try again.")
	}
	cloudProvider, err := enum.FromString[globalcommonv1.CloudProvider_Name](provider)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid cloudProvider, please check and try again.")
	}
	globalRegion, err := enum.RegionFromString(provider, region)
	if err != nil || globalRegion == globalcommonv1.Region_NAME_UNSPECIFIED {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "region %s is not supported", region)
	}

	globalCloudProvider := globalcommonv1.CloudProvider_Name(cloudProvider)
	if request.GetServicePlan() != openapicommonv1beta1.ServicePlan_Premium {
		return nil, bizerr.New(bizerr.ErrCodeParams, "%s", appcommon.NotSupportedCmekErrorMsg)
	}
	if globalCloudProvider != globalcommonv1.CloudProvider_AWS && globalCloudProvider != globalcommonv1.CloudProvider_ALICLOUD {
		return nil, bizerr.New(bizerr.ErrCodeParams, "%s", appcommon.NotSupportedCmekErrorMsg)
	}

	globalPrincipal, err := s.nextgenCli.GetCmekAccessIamPrincipal(ctx, &globalngv1.GetCmekAccessIamPrincipalRequest{
		OrganizationId:  reqMeta.OrgID,
		CloudProviderId: globalCloudProvider,
		RegionId:        globalRegion,
		ServicePlan:     common.CvtGlobalServicePlan(request.GetServicePlan()),
	})
	if err != nil {
		return nil, err
	}

	openapiPrincipal := &openapingv1beta2.CmekAccessIamPrincipal{
		RegionId:    request.RegionId,
		ServicePlan: request.ServicePlan,
	}

	switch globalCloudProvider {
	case globalcommonv1.CloudProvider_AWS:
		openapiPrincipal.Principal = &openapingv1beta2.CmekAccessIamPrincipal_Aws{
			Aws: appcommon.CvtGlobalAwsCmekPrincipalToOpenapi(globalPrincipal.GetAws()),
		}
	case globalcommonv1.CloudProvider_ALICLOUD:
		openapiPrincipal.Principal = &openapingv1beta2.CmekAccessIamPrincipal_Aliyun{
			Aliyun: appcommon.CvtGlobalAliyunCmekPrincipalToOpenapi(globalPrincipal.GetAliyun()),
		}
	default:
		return nil, bizerr.New(bizerr.ErrCodeParams, "%s", appcommon.NotSupportedCmekErrorMsg)
	}
	return openapiPrincipal, nil
}

func (s serverImpl) VerifyCmekAccessIamPrincipal(ctx context.Context,
	request *openapingv1beta2.VerifyCmekAccessIamPrincipalRequest,
) (*openapingv1beta2.VerifyCmekAccessIamPrincipalResponse, error) {
	ctx, span := tracer.Start(ctx, "GetCmekAccessIamPrincipal")
	defer span.End()

	reqMeta, err := metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	provider, region, err := common.ParseOpenApiRegionNameOrId(request.GetKey().GetRegionId())
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region, please check and try again.")
	}
	cloudProvider, err := enum.FromString[globalcommonv1.CloudProvider_Name](provider)
	if err != nil {
		return nil, err
	}
	globalRegion, err := enum.RegionFromString(provider, region)
	if err != nil || globalRegion == globalcommonv1.Region_NAME_UNSPECIFIED {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "region %s is not supported", region)
	}

	globalCloudProvider := globalcommonv1.CloudProvider_Name(cloudProvider)
	if request.GetKey().GetServicePlan() != openapicommonv1beta1.ServicePlan_Premium {
		return nil, bizerr.New(bizerr.ErrCodeParams, "%s", appcommon.NotSupportedCmekErrorMsg)
	}
	if globalCloudProvider != globalcommonv1.CloudProvider_AWS && globalCloudProvider != globalcommonv1.CloudProvider_ALICLOUD {
		return nil, bizerr.New(bizerr.ErrCodeParams, "%s", appcommon.NotSupportedCmekErrorMsg)
	}

	globalCmek, err := appcommon.BuildGlobalCmek(
		reqMeta.OrgID,
		globalCloudProvider,
		globalRegion,
		common.CvtGlobalServicePlan(request.GetKey().GetServicePlan()),
		request.GetKey(),
	)
	if err != nil {
		return nil, err
	}

	var clusterID uint64
	if request.GetTidbId() != "" {
		clusterID, err = strconv.ParseUint(request.GetTidbId(), 10, 64)
		if err != nil {
			return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid TiDB ID")
		}
	}

	verifyResult, err := s.nextgenCli.VerifyCmekAccessIamPrincipal(ctx, &globalngv1.VerifyCmekAccessIamPrincipalRequest{
		Key:       globalCmek,
		ClusterId: clusterID,
	})
	if err != nil {
		return nil, err
	}

	return &openapingv1beta2.VerifyCmekAccessIamPrincipalResponse{
		Valid:      verifyResult.Valid,
		FailReason: verifyResult.GetFailReason(),
	}, nil
}
