package rbac

import (
	"sync"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/tiinf/sdk/rbac/common"
	"github.com/tidbcloud/tiinf/sdk/rbac/helperimpl"
)

// -------- supply method to use ------

var (
	onceCheckerWithCommonParam     PermissionChecker
	onceCheckerWithCommonParamInit sync.Once

	onceCheckerWithInitParam     PermissionChecker
	onceCheckerWithInitParamInit sync.Once
)

type PermissionCheckerCommonParam struct {
	AccountClient           account.AccountAPIServiceClient
	IdentityF               common.GetIdentityFunc
	PathPattern2ResourceMap map[string]string
	PathWhitelist           []string
	ResourceCascadeF        common.CheckCascadeResourceFunc
}

type PermissionCheckerInitParam struct {
	IdentityH        common.IdentityHelper
	ResourceH        common.ResourceHelper
	PermissionH      common.PermissionHelper
	RequestHs        []common.RequestHelper
	ResourceCascadeH common.ResourceCascadeChecker
}

func GetPermissionCheckerWithCommonParam(commonParam *PermissionCheckerCommonParam) PermissionChecker {
	onceCheckerWithCommonParamInit.Do(func() {
		var permissionH common.PermissionHelper = helperimpl.DefaultCachedPermissionHelper
		if commonParam.AccountClient != nil {
			permissionH = helperimpl.NewCustomClientPermissionHelper(commonParam.AccountClient)
		}

		initParam := &PermissionCheckerInitParam{
			IdentityH:        commonParam.IdentityF,
			ResourceH:        helperimpl.NewMapStoreResourceHelper(commonParam.PathPattern2ResourceMap),
			PermissionH:      permissionH,
			ResourceCascadeH: commonParam.ResourceCascadeF,
			RequestHs:        []common.RequestHelper{helperimpl.NewWhitelistRequestHelper(commonParam.PathWhitelist...)},
		}

		onceCheckerWithCommonParam = innerInitPermissionChecker(initParam)
	})
	if onceCheckerWithCommonParam == nil {
		panic("PermissionChecker is nil")
	}
	return onceCheckerWithCommonParam
}

func GetPermissionCheckerWithInitParam(initParam *PermissionCheckerInitParam) PermissionChecker {
	onceCheckerWithInitParamInit.Do(func() {
		onceCheckerWithInitParam = innerInitPermissionChecker(initParam)
	})
	if onceCheckerWithInitParam == nil {
		panic("PermissionChecker is nil")
	}
	return onceCheckerWithInitParam
}

func NewPermissionCheckerWithInitParam(initParam *PermissionCheckerInitParam) PermissionChecker {
	checker := innerInitPermissionChecker(initParam)
	if checker == nil {
		panic("PermissionChecker is nil")
	}
	return checker
}

// inner use to init permission checker
func innerInitPermissionChecker(initParam *PermissionCheckerInitParam) PermissionChecker {
	checker := NewPermissionChecker(initParam.IdentityH, initParam.ResourceH, initParam.PermissionH)

	requestHs := initParam.RequestHs
	if requestHs != nil && len(requestHs) > 0 {
		for _, h := range requestHs {
			checker.RegisterRequestHelper(h)
		}
	}

	if initParam.ResourceCascadeH != nil {
		checker.SetResourceCascadeChecker(initParam.ResourceCascadeH)
	}

	return checker
}

//   -----------------      deprecated  start     --------------------------

var (
	onceCheckerWithDefaultHelper     PermissionChecker
	onceCheckerWithDefaultHelperInit sync.Once
)

// Deprecated
func GetPermissionCheckerWithDefaultHelper(
	identityF common.GetIdentityFunc,
	pathPattern2ResourceMap map[string]string,
	pathWhitelist ...string) PermissionChecker {
	onceCheckerWithDefaultHelperInit.Do(func() {
		resourceH := helperimpl.NewMapStoreResourceHelper(pathPattern2ResourceMap)
		requestH := helperimpl.NewWhitelistRequestHelper(pathWhitelist...)
		permissionH := helperimpl.DefaultCachedPermissionHelper

		onceCheckerWithDefaultHelper = InitPermissionChecker(identityF, resourceH, permissionH, requestH)
	})
	if onceCheckerWithDefaultHelper == nil {
		panic("PermissionChecker is nil")
	}
	return onceCheckerWithDefaultHelper
}

var (
	onceCheckerWithCustomClient     PermissionChecker
	onceCheckerWithCustomClientInit sync.Once
)

// Deprecated
func GetPermissionCheckerWithAccountClient(
	client account.AccountAPIServiceClient,
	identityF common.GetIdentityFunc,
	pathPattern2ResourceMap map[string]string,
	pathWhitelist ...string) PermissionChecker {
	onceCheckerWithCustomClientInit.Do(func() {
		resourceH := helperimpl.NewMapStoreResourceHelper(pathPattern2ResourceMap)
		requestH := helperimpl.NewWhitelistRequestHelper(pathWhitelist...)
		permissionH := helperimpl.NewCustomClientPermissionHelper(client)

		onceCheckerWithCustomClient = InitPermissionChecker(identityF, resourceH, permissionH, requestH)
	})
	if onceCheckerWithCustomClient == nil {
		panic("PermissionChecker is nil")
	}
	return onceCheckerWithCustomClient
}

var (
	onceChecker     PermissionChecker
	onceCheckerInit sync.Once
)

// Deprecated
func GetPermissionChecker(
	identityH common.IdentityHelper,
	resourceH common.ResourceHelper,
	permissionH common.PermissionHelper,
	requestHs ...common.RequestHelper) PermissionChecker {
	onceCheckerInit.Do(func() {
		onceChecker = InitPermissionChecker(identityH, resourceH, permissionH, requestHs...)
	})
	if onceChecker == nil {
		panic("PermissionChecker is nil")
	}
	return onceChecker
}

// Deprecated
func InitPermissionChecker(
	identityH common.IdentityHelper,
	resourceH common.ResourceHelper,
	permissionH common.PermissionHelper,
	requestHs ...common.RequestHelper) PermissionChecker {
	checker := NewPermissionChecker(identityH, resourceH, permissionH)
	if requestHs != nil && len(requestHs) > 0 {
		for _, h := range requestHs {
			checker.RegisterRequestHelper(h)
		}
	}
	return checker
}

//   -----------------      deprecated  end     --------------------------
