package auth

import (
	"context"
	"sync"
)

var (
	onceDirectCallChecker     PermissionChecker
	onceDirectCallCheckerInit sync.Once
)

func CheckIdentityPermission(ctx context.Context, param *CheckPermissionParam) (*CheckPermissionRet, error) {
	dParam := GenAccessParam4DirectCalled(param)
	var checker PermissionChecker
	if param.GoDDBPermitCheck {
		checker, _ = GetDirectCallDDBCrossRegionPermissionChecker()
	} else {
		checker, _ = GetDirectCallPermissionChecker()
	}

	dRet, err := checker.Handle(ctx, dParam)
	if err != nil {
		return nil, err
	}
	ret := CheckPermissionRet{
		HasPermission: dRet.Code == AccessRetRelease,
		Message:       dRet.Msg,
	}
	return &ret, nil
}

func GetDirectCallPermissionChecker() (PermissionChecker, error) {
	onceDirectCallCheckerInit.Do(func() {
		identityH, _ := NewMetadataStoreIdentityPlugin(AccessMetadataIdentityTyeKey, AccessMetadataIdentityValKey)
		resourceH, _ := NewMetadataStoreResourcePlugin(AccessMetadataResourceKey, AccessMetadataResourceParamKey)
		permissionH, _ := NewDefaultPermissionPlugin()
		option := PermissionCheckerOption{
			PermissionCheckClosed: false,
			EnableLog:             true,
		}
		onceDirectCallChecker, _ = NewPermissionChecker(identityH, resourceH, permissionH, nil, nil, option)
	})
	return onceDirectCallChecker, nil
}

func GetDirectCallDDBCrossRegionPermissionChecker() (PermissionChecker, error) {
	onceDirectCallCheckerInit.Do(func() {
		identityH, _ := NewMetadataStoreIdentityPlugin(AccessMetadataIdentityTyeKey, AccessMetadataIdentityValKey)
		resourceH, _ := NewMetadataStoreResourcePlugin(AccessMetadataResourceKey, AccessMetadataResourceParamKey)
		permissionH := DefaultRegionApiKeyPermissionHelper
		option := PermissionCheckerOption{
			PermissionCheckClosed: false,
			EnableLog:             true,
		}
		onceDirectCallChecker, _ = NewPermissionChecker(identityH, resourceH, permissionH, nil, nil, option)
	})
	return onceDirectCallChecker, nil
}

type CheckPermissionParam struct {
	IdentityTye      AccessIdentityType
	IdentityVal      string
	ResourceUri      string
	ResourceParam    map[string]string
	GoDDBPermitCheck bool
}

type CheckPermissionRet struct {
	HasPermission bool
	Message       string
}

func GenAccessParam4DirectCalled(param *CheckPermissionParam) *AccessParam {
	return &AccessParam{
		Metadata: map[string]interface{}{
			AccessMetadataIdentityTyeKey:   param.IdentityTye,
			AccessMetadataIdentityValKey:   param.IdentityVal,
			AccessMetadataResourceKey:      param.ResourceUri,
			AccessMetadataResourceParamKey: param.ResourceParam,
		},
	}
}
