package helperimpl

import (
	"context"
	"errors"
	"fmt"
	"regexp"
	"strings"

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

type whitelistRequestHelper struct {
	// path_pattern -> method
	whitelistMap map[string]string
}

func NewWhitelistRequestHelper(whitelist ...string) common.RequestHelper {
	formatWhitelistMap, err := validateAndFormatWhitelist(whitelist...)
	if err != nil {
		panic(err.Error())
	}
	return &whitelistRequestHelper{
		whitelistMap: formatWhitelistMap,
	}
}

func NewWhitelistRequestFunc(whitelist ...string) common.ReleaseRequestFunc {
	helper := NewWhitelistRequestHelper(whitelist...)
	return func(ctx context.Context, param *common.AccessParam) (bool, error) {
		return helper.ReleaseRequest(ctx, param)
	}
}

func (d *whitelistRequestHelper) ReleaseRequest(_ context.Context, param *common.AccessParam) (bool, error) {
	if d.whitelistMap == nil || len(d.whitelistMap) == 0 {
		return false, nil
	}
	path := common.GetRequestPath(param)
	method := common.GetRequestMethod(param)
	for p, m := range d.whitelistMap {
		if !regexp.MustCompile(p).MatchString(path) {
			continue
		}
		if m == common.LOCAL_DEFAULT_MOTHOD || m == strings.ToLower(method) {
			return true, nil
		}
	}
	return false, nil
}

func validateAndFormatWhitelist(whitelist ...string) (map[string]string, error) {
	var formatWhitelistMap = map[string]string{}
	if whitelist != nil && len(whitelist) > 0 {
		for _, wl := range whitelist {
			if wl == "" {
				return nil, errors.New("whitelist path is blank")
			}
			path, method, err := common.ParsePathPattern(wl)
			if err != nil {
				return nil, err
			}
			exactMatchPath := fmt.Sprintf(common.EXACT_MATCH_FORMATTER, path)
			_, err = regexp.Compile(exactMatchPath)
			if err != nil {
				return nil, errors.New(fmt.Sprintf("whitelist path invalid: %s, err: %s", wl, err.Error()))
			}
			if method == "" {
				method = common.LOCAL_DEFAULT_MOTHOD
			}
			formatWhitelistMap[exactMatchPath] = strings.ToLower(method)
		}
	}
	return formatWhitelistMap, nil
}
