package useadapter

import (
	"context"
	"sync"

	"github.com/tidbcloud/tiinf/sdk/rbac"
	"github.com/tidbcloud/tiinf/sdk/rbac/common"
	"github.com/tidbcloud/tiinf/sdk/rbac/helperimpl"
)

// -------- direct called by biz in logic to check permission ------------------

// CheckIdentityPermission must call DefaultCachedPermissionDP.SetEndpoint to set endpoint before use
func CheckIdentityPermission(ctx context.Context, identity, resource string, resourceParam map[string]string) (
	hasPermission bool, msg string, err error) {

	directCalledChecker := rbac.GetPermissionCheckerWithInitParam(&rbac.PermissionCheckerInitParam{
		IdentityH:   helperimpl.DefaultMetadataStoreIdentityHelper,
		ResourceH:   helperimpl.DefaultMetadataStoreResourceHelper,
		PermissionH: helperimpl.DefaultCachedPermissionHelper,
	})
	param := GenAccessParam4DirectCalled(identity, resource, resourceParam)

	result, err := directCalledChecker.Handle(ctx, param)
	if err != nil {
		return false, "internal check error", err
	}
	hasPermission = false
	if result.Code == common.RSP_CODE_RELEASE {
		hasPermission = true
	}
	return hasPermission, result.Msg, nil
}

func CheckApiKeyPermission(ctx context.Context, identity, resource string, resourceParam map[string]string) (
	hasPermission bool, msg string, err error) {

	param := GenAccessParam4DirectCalled(identity, resource, resourceParam)

	directCalledChecker := getApiKeyPermissionChecker()
	result, err := directCalledChecker.Handle(ctx, param)
	if err != nil {
		return false, "internal check error", err
	}
	hasPermission = false
	if result.Code == common.RSP_CODE_RELEASE {
		hasPermission = true
	}
	return hasPermission, result.Msg, nil
}

var (
	apiKeyChecker     rbac.PermissionChecker
	apiKeyCheckerInit sync.Once
)

func getApiKeyPermissionChecker() rbac.PermissionChecker {
	apiKeyCheckerInit.Do(func() {
		apiKeyChecker = rbac.NewPermissionCheckerWithInitParam(&rbac.PermissionCheckerInitParam{
			IdentityH:   helperimpl.DefaultMetadataStoreIdentityHelper,
			ResourceH:   helperimpl.DefaultMetadataStoreResourceHelper,
			PermissionH: helperimpl.DefaultApiKeyPermissionHelper,
		})
	})
	if apiKeyChecker == nil {
		panic("PermissionChecker is nil")
	}
	return apiKeyChecker
}

// You may need to call DefaultRegionApiKeyPermissionHelper.`SetAwsBasic“ && `SetDynamoDBTableName“ to set aws credential and dynamodb table name before use this function
func CheckRegionApiKeyPermission(ctx context.Context, identity, resource string, resourceParam map[string]string) (
	hasPermission bool, msg string, err error) {

	directCalledChecker := rbac.GetRegionPermissionChecker(
		helperimpl.DefaultMetadataStoreIdentityHelper,
		helperimpl.DefaultRegionMetadataStoreResourceHelper,
		helperimpl.DefaultRegionApiKeyPermissionHelper,
		nil,
	)
	param := GenAccessParam4DirectCalled(identity, resource, resourceParam)
	result, err := directCalledChecker.Handle(ctx, param)
	if err != nil {
		return false, "internal check error", err
	}
	hasPermission = false
	if result.Code == common.RSP_CODE_RELEASE {
		hasPermission = true
	}
	return hasPermission, result.Msg, nil
}

func GenAccessParam4DirectCalled(identity, resource string, resourceParam map[string]string) *common.AccessParam {
	param := common.AccessParam{
		Metadata: map[string]interface{}{
			common.METADATA_IDENTITY:       identity,
			common.METADATA_RESOURCE:       resource,
			common.METADATA_RESOURCE_PARAM: resourceParam,
		},
	}
	return &param
}
