package cmek

import (
	"context"
	"strconv"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/enum"
)

func (s serverImpl) GetCustomerManagedEncryptionKey(
	ctx context.Context,
	request *tidbmgmtservicev1.GetCustomerManagedEncryptionKeyRequest,
) (*tidbmgmtservicev1.CustomerManagedEncryptionKey, error) {
	cmekId, err := strconv.ParseUint(request.CustomerManagedEncryptionKeyId, 10, 64)
	if err != nil {
		return nil, err
	}

	globalDedicatedCmek, err := s.dedicatedCli.GetCustomerManagedEncryptionKey(
		ctx,
		&globaldedicatedv1.GetCustomerManagedEncryptionKeyRequest{
			CustomerManagedEncryptionKeyId: cmekId,
		},
	)

	if err != nil {
		return nil, err
	}

	cmek := cmekToInternalAPI(globalDedicatedCmek)
	return cmek, nil
}

func (s serverImpl) ListCustomerManagedEncryptionKeys(
	ctx context.Context,
	request *tidbmgmtservicev1.ListCustomerManagedEncryptionKeysRequest,
) (*tidbmgmtservicev1.ListCustomerManagedEncryptionKeysResponse, error) {
	globalDedicatedReq, err := listRequestToDedicatedGlobalAPI(request)
	if err != nil {
		return nil, err
	}
	globalDedicatedResp, err := s.dedicatedCli.ListCustomerManagedEncryptionKeys(ctx, globalDedicatedReq)

	if err != nil {
		return nil, err
	}

	cmeks := make(
		[]*tidbmgmtservicev1.CustomerManagedEncryptionKey,
		0,
		len(globalDedicatedResp.CustomerManagedEncryptionKeys),
	)

	for _, cmek := range globalDedicatedResp.CustomerManagedEncryptionKeys {
		cmeks = append(cmeks, cmekToInternalAPI(cmek))
	}

	resp := &tidbmgmtservicev1.ListCustomerManagedEncryptionKeysResponse{}
	resp.Cmeks = cmeks
	return resp, nil
}

func listRequestToDedicatedGlobalAPI(
	mgmtRequest *tidbmgmtservicev1.ListCustomerManagedEncryptionKeysRequest,
) (*globaldedicatedv1.ListCustomerManagedEncryptionKeysRequest, error) {
	request := &globaldedicatedv1.ListCustomerManagedEncryptionKeysRequest{}

	if mgmtRequest.GetProjectId() != "" {
		projectId, err := strconv.ParseUint(mgmtRequest.GetProjectId(), 10, 64)
		if err != nil {
			return nil, bizerr.New(bizerr.ErrCodeParams, "project id is invalid")
		}
		request.ProjectIds = []uint64{projectId}
	}

	if mgmtRequest.GetRegionId() != "" {
		regionName, err := enum.FromString[globalcommonv1.Region_Name](mgmtRequest.GetRegionId())
		if err != nil {
			return nil, bizerr.New(bizerr.ErrCodeParams, "region %s is not supported", mgmtRequest.GetRegionId())
		}

		request.RegionIds = []globalcommonv1.Region_Name{
			globalcommonv1.Region_Name(regionName),
		}
	}

	if mgmtRequest.GetCloudProvider() != "" {
		cloudProviderName, err := enum.FromString[globalcommonv1.CloudProvider_Name](mgmtRequest.GetCloudProvider())
		if err != nil {
			return nil, bizerr.New(
				bizerr.ErrCodeParams,
				"cloud provider %s is not supported",
				mgmtRequest.GetCloudProvider(),
			)
		}

		request.CloudProviderIds = []globalcommonv1.CloudProvider_Name{
			globalcommonv1.CloudProvider_Name(cloudProviderName),
		}
	}

	return request, nil
}

func cmekToInternalAPI(
	dedicatedGlobalCmek *globaldedicatedv1.CustomerManagedEncryptionKey,
) *tidbmgmtservicev1.CustomerManagedEncryptionKey {
	if dedicatedGlobalCmek == nil {
		return nil
	}
	cmek := &tidbmgmtservicev1.CustomerManagedEncryptionKey{
		CustomerManagedEncryptionKeyId: strconv.FormatUint(dedicatedGlobalCmek.Id, 10),
		CloudProvider:                  dedicatedGlobalCmek.GetCloudProviderId().String(),
		RegionId:                       dedicatedGlobalCmek.GetRegionId().String(),
		ProjectId:                      strconv.FormatUint(dedicatedGlobalCmek.ProjectId, 10),
	}
	switch dedicatedGlobalCmek.GetCloudProviderId() {
	case globalcommonv1.CloudProvider_AWS:
		cmek.Key = &tidbmgmtservicev1.CustomerManagedEncryptionKey_AwsKms{
			AwsKms: &tidbmgmtservicev1.AwsKms{
				KmsKeyArn: dedicatedGlobalCmek.GetAwsKeyArn(),
			},
		}
	case globalcommonv1.CloudProvider_AZURE:
		cmek.Key = &tidbmgmtservicev1.CustomerManagedEncryptionKey_AzureKeyVault{
			AzureKeyVault: &tidbmgmtservicev1.AzureKeyVault{
				KeyVaultKey:  dedicatedGlobalCmek.GetAzureKeyVault().GetKeyVaultKey(),
				KeyVaultName: dedicatedGlobalCmek.GetAzureKeyVault().GetKeyVaultName(),
				AppRegistration: &tidbmgmtservicev1.AzureAppRegistration{
					AppRegistrationId: dedicatedGlobalCmek.GetAzureKeyVault().
						GetAzureAppRegistration().
						GetAppRegistrationId(),
					AppRegistrationName: dedicatedGlobalCmek.GetAzureKeyVault().
						GetAzureAppRegistration().
						GetAppRegistrationName(),
					AppRegistrationUmi: dedicatedGlobalCmek.GetAzureKeyVault().
						GetAzureAppRegistration().
						GetAppRegistrationUmi(),
				},
			},
		}
	}

	return cmek
}
