package runtimeidentity

import (
	"context"
	"errors"
	"slices"
	"strings"

	"github.com/nexuscrm/backend/internal/runtimeapi"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/delegationv1"
)

// NewSessionCapabilityPolicy creates the explicit operator-owned mapping from
// existing session scopes to neutral Runtime capabilities. No scope and no
// mapping both mean no grant.
func NewSessionCapabilityPolicy(scopeCapabilities map[string][]string) (SessionCapabilityAuthority, error) {
	if len(scopeCapabilities) == 0 {
		return nil, errors.New("runtime session capability policy: at least one explicit scope mapping is required")
	}
	owned := make(map[string][]string, len(scopeCapabilities))
	for scope, capabilities := range scopeCapabilities {
		if strings.TrimSpace(scope) != scope || scope == "" || len(capabilities) == 0 {
			return nil, errors.New("runtime session capability policy: canonical scope and non-empty grants are required")
		}
		copyCapabilities := append([]string(nil), capabilities...)
		slices.Sort(copyCapabilities)
		copyCapabilities = slices.Compact(copyCapabilities)
		if err := delegationv1.ValidateCapabilityGrants(copyCapabilities); err != nil {
			return nil, errors.New("runtime session capability policy: invalid capability grant")
		}
		owned[scope] = copyCapabilities
	}
	return func(_ context.Context, state runtimeapi.RuntimeSessionState) ([]string, error) {
		granted := map[string]struct{}{}
		for _, scope := range strings.Fields(state.User.Scope) {
			for _, capability := range owned[scope] {
				granted[capability] = struct{}{}
			}
		}
		if len(granted) == 0 {
			return nil, nil
		}
		result := make([]string, 0, len(granted))
		for capability := range granted {
			result = append(result, capability)
		}
		slices.Sort(result)
		return result, nil
	}, nil
}
