package rbac

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/pingcap/errors"
)

type whitelistRequest struct {
	whitelistMap map[string]string
}

func NewWhitelistRequest(whitelist []string) (*whitelistRequest, error) {
	m, err := validateAndFormatWhitelist(whitelist)
	if err != nil {
		return nil, err
	}

	return &whitelistRequest{
		whitelistMap: m,
	}, nil
}

func (d *whitelistRequest) Request(path, method string) (bool, error) {
	if len(d.whitelistMap) == 0 {
		return false, nil
	}
	for p, m := range d.whitelistMap {
		if !regexp.MustCompile(p).MatchString(path) {
			continue
		}
		if m == LOCAL_DEFAULT_METHOD || m == strings.ToLower(method) {
			return true, nil
		}
	}
	return false, nil
}

func validateAndFormatWhitelist(whitelist []string) (map[string]string, error) {
	formatWhitelistMap := map[string]string{}
	if len(whitelist) > 0 {
		for _, wl := range whitelist {
			if wl == "" {
				return nil, errors.New("whitelist path is blank")
			}
			path, method, err := ParsePathPattern(wl)
			if err != nil {
				return nil, err
			}
			exactMatchPath := fmt.Sprintf(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 = LOCAL_DEFAULT_METHOD
			}
			formatWhitelistMap[exactMatchPath] = strings.ToLower(method)
		}
	}
	return formatWhitelistMap, nil
}
