// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0

package api

import (
	"fmt"
	"reflect"
	"regexp"
	"slices"
	"strings"
)

// +kubebuilder:object:generate=true
type ForbiddenListSpec struct {
	Exact []string `json:"denied,omitempty"`
	Regex string   `json:"deniedRegex,omitempty"`
}

func (in ForbiddenListSpec) ExactMatch(value string) bool {
	return slices.Contains(in.Exact, value)
}

func (in ForbiddenListSpec) RegexMatch(value string) (ok bool) {
	if len(in.Regex) > 0 {
		ok = regexp.MustCompile(in.Regex).MatchString(value)
	}

	return ok
}

type ForbiddenError struct {
	key  string
	spec ForbiddenListSpec
}

func NewForbiddenError(key string, forbiddenSpec ForbiddenListSpec) error {
	return &ForbiddenError{
		key:  key,
		spec: forbiddenSpec,
	}
}

func (f ForbiddenError) Error() string {
	return fmt.Sprintf("%s is forbidden for the current Tenant. %s", f.key, f.appendForbiddenError())
}

//nolint:predeclared,revive
func (f *ForbiddenError) appendForbiddenError() (append string) {
	append += "Forbidden are "
	if len(f.spec.Exact) > 0 {
		append += fmt.Sprintf("one of the following (%s)", strings.Join(f.spec.Exact, ", "))
		if len(f.spec.Regex) > 0 {
			append += " or "
		}
	}

	if len(f.spec.Regex) > 0 {
		append += fmt.Sprintf("matching the regex %s", f.spec.Regex)
	}

	return append
}

func ValidateForbidden(metadata map[string]string, forbiddenList ForbiddenListSpec) error {
	if reflect.DeepEqual(ForbiddenListSpec{}, forbiddenList) {
		return nil
	}

	for key := range metadata {
		var forbidden, matched bool

		forbidden = forbiddenList.ExactMatch(key)
		matched = forbiddenList.RegexMatch(key)

		if forbidden || matched {
			return NewForbiddenError(
				key,
				forbiddenList,
			)
		}
	}

	return nil
}
