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

package invalidator

import (
	"context"
	"fmt"

	"github.com/go-logr/logr"

	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
	"github.com/projectcapsule/capsule/internal/cache"
	"github.com/projectcapsule/capsule/pkg/api/rules"
	"github.com/projectcapsule/capsule/pkg/api/runtime"
)

func (r *CacheInvalidator) rebuildRegexCache(ctx context.Context, log logr.Logger) error {
	ruleStatuses := &capsulev1beta2.RuleStatusList{}
	if err := r.List(ctx, ruleStatuses); err != nil {
		return err
	}

	log.V(5).Info("rebuilding regex cache",
		"regexesBefore", r.RegexCache.Stats(),
		"ruleStatuses", len(ruleStatuses.Items),
	)

	r.RegexCache.Reset()

	expressions := make(map[string]runtime.ExpressionRegex)

	for i := range ruleStatuses.Items {
		rs := &ruleStatuses.Items[i]

		collectRegexExpressionsFromNamespaceRules(expressions, rs.Spec)
		collectRegexExpressionsFromNamespaceRules(expressions, rs.Status.Rules)
	}

	for _, expr := range expressions {
		if _, _, err := r.RegexCache.GetOrCompile(expr); err != nil {
			return fmt.Errorf("build regex cache entry %q: %w", expr.Expression, err)
		}
	}

	log.V(5).Info("rebuilt regex cache",
		"uniqueExpressions", len(expressions),
		"regexesAfter", r.RegexCache.Stats(),
	)

	return nil
}

func collectRegexExpressionsFromNamespaceRules(
	set map[string]runtime.ExpressionRegex,
	r []*rules.NamespaceRuleBodyNamespace,
) {
	for _, rule := range r {
		collectRegexExpressionsFromNamespaceRule(set, rule)
	}
}

func collectRegexExpressionsFromNamespaceRule(
	set map[string]runtime.ExpressionRegex,
	rule *rules.NamespaceRuleBodyNamespace,
) {
	if rule == nil {
		return
	}

	if rule.Enforce == nil {
		return
	}

	for _, registry := range rule.Enforce.Workloads.Registries {
		expr := registry.ExpressionRegex
		if expr.Expression == "" {
			continue
		}

		set[cache.HashRegex(expr)] = expr
	}

	for _, scheduler := range rule.Enforce.Workloads.Schedulers {
		expr := scheduler.ExpressionRegex
		if expr.Expression == "" {
			continue
		}

		set[cache.HashRegex(expr)] = expr
	}

	for _, metadataRule := range rule.Enforce.Metadata {
		for selector := range metadataRule.Labels {
			expr := rules.MetadataKeyExpression(selector)
			set[cache.HashRegex(expr)] = expr
		}

		for selector := range metadataRule.Annotations {
			expr := rules.MetadataKeyExpression(selector)
			set[cache.HashRegex(expr)] = expr
		}
	}
}
