package connector_webhooks

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	connectorcapabilities "github.com/pingcap-inc/nexuscrm-connectors/features/connector/capabilities"
	connector_packstate "github.com/pingcap-inc/nexuscrm-connectors/features/connector/packstate"
	"github.com/pingcap-inc/nexuscrm-connectors/features/webhooks"
)

const (
	defaultWebhookIngressSnapshotCacheTTL     = 30 * time.Second
	defaultWebhookIngressSnapshotLoadLimit    = 1500 * time.Millisecond
	defaultWebhookIngressGuardRefreshCooldown = 5 * time.Second
)

type webhookIngressSnapshotCache struct {
	mu          sync.Mutex
	ttl         time.Duration
	packs       map[webhookIngressPackCacheKey]webhookIngressPackCacheEntry
	secrets     map[webhookIngressSecretCacheKey]webhookIngressSecretCacheEntry
	loads       map[string]*webhookIngressSharedLoad
	packEpoch   map[webhookIngressPackCacheKey]*webhookIngressEpoch
	secretEpoch map[webhookIngressSecretCacheKey]*webhookIngressEpoch
	now         func() time.Time
}

type webhookIngressEpoch struct {
	refs         int
	latestLoadID uint64
}

type webhookIngressSharedLoad struct {
	done    chan struct{}
	cancel  context.CancelFunc
	value   any
	err     error
	waiters int
	shared  bool
}

type webhookIngressSharedLoadResult struct {
	value  any
	err    error
	shared bool
}

type webhookIngressPackCacheKey struct {
	namespace string
}

type webhookIngressPackCacheEntry struct {
	row               connector_packstate.ConnectorPackRow
	expiresAt         time.Time
	guardRefreshAfter time.Time
}

type webhookIngressVerifierCacheKey struct {
	namespace     string
	packInstallID string
}

type webhookIngressSecretCacheKey struct {
	namespace     string
	secretName    string
	packInstallID string
}

type webhookIngressSecretCacheEntry struct {
	secret    webhooks.ResolvedWebhookSecret
	expiresAt time.Time
}

type webhookIngressPackResolveResult struct {
	row *connector_packstate.ConnectorPackRow
	ok  bool
}

type webhookIngressSnapshotDeadlineContract string

const (
	webhookIngressSnapshotDeadlineDefault webhookIngressSnapshotDeadlineContract = "default"
	webhookIngressSnapshotDeadlineAckDrop webhookIngressSnapshotDeadlineContract = "ack_drop"
)

func newWebhookIngressSnapshotCache(ttl time.Duration) *webhookIngressSnapshotCache {
	if ttl <= 0 {
		return nil
	}
	return &webhookIngressSnapshotCache{
		ttl:         ttl,
		packs:       map[webhookIngressPackCacheKey]webhookIngressPackCacheEntry{},
		secrets:     map[webhookIngressSecretCacheKey]webhookIngressSecretCacheEntry{},
		loads:       map[string]*webhookIngressSharedLoad{},
		packEpoch:   map[webhookIngressPackCacheKey]*webhookIngressEpoch{},
		secretEpoch: map[webhookIngressSecretCacheKey]*webhookIngressEpoch{},
		now:         time.Now,
	}
}

func (c *webhookIngressSnapshotCache) load(
	ctx context.Context,
	key string,
	resolve func(context.Context) (any, error),
) (webhookIngressSharedLoadResult, error) {
	c.mu.Lock()
	inflight := c.loads[key]
	if inflight != nil {
		inflight.waiters++
		inflight.shared = true
		c.mu.Unlock()
	} else {
		loadCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), defaultWebhookIngressSnapshotLoadLimit)
		inflight = &webhookIngressSharedLoad{
			done:    make(chan struct{}),
			cancel:  cancel,
			waiters: 1,
		}
		c.loads[key] = inflight
		c.mu.Unlock()
		releaseCapacity := retainWebhookIngressCapacityLease(ctx)
		go func() {
			defer func() {
				if recover() != nil {
					inflight.value = nil
					inflight.err = fmt.Errorf("connector_webhooks: snapshot resolver panicked")
				}
				cancel()
				releaseCapacity()
				c.mu.Lock()
				if c.loads[key] == inflight {
					delete(c.loads, key)
				}
				close(inflight.done)
				c.mu.Unlock()
			}()
			inflight.value, inflight.err = resolve(loadCtx)
		}()
	}

	select {
	case <-ctx.Done():
		c.mu.Lock()
		if c.loads[key] == inflight {
			inflight.waiters--
			if inflight.waiters == 0 {
				// Keep the load registered until the resolver actually exits.
				// Cancel-aware resolvers stop promptly; cancellation-ignoring
				// resolvers remain the sole owner so retries cannot overlap them.
				inflight.cancel()
			}
		}
		c.mu.Unlock()
		return webhookIngressSharedLoadResult{}, ctx.Err()
	case <-inflight.done:
		return webhookIngressSharedLoadResult{
			value:  inflight.value,
			err:    inflight.err,
			shared: inflight.shared,
		}, nil
	}
}

func webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint bool) webhookIngressSnapshotDeadlineContract {
	if ackDropEndpoint {
		return webhookIngressSnapshotDeadlineAckDrop
	}
	return webhookIngressSnapshotDeadlineDefault
}

func (d *Dispatcher) resolveWebhookPack(ctx context.Context, namespace string, receiptMode, ackDropEndpoint bool) (*connector_packstate.ConnectorPackRow, bool, error) {
	if d == nil || !receiptMode || d.ingressCache == nil || d.requireLivePackAuthority {
		return d.resolvePack(ctx, namespace)
	}
	return d.ingressCache.resolvePack(ctx, d.resolvePack, namespace, webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint))
}

func (d *Dispatcher) resolveWebhookSecret(ctx context.Context, namespace, secretName, packInstallID string, receiptMode, ackDropEndpoint bool) (*webhooks.ResolvedWebhookSecret, bool, error) {
	if d == nil || d.resolveSecret == nil {
		return nil, false, fmt.Errorf("connector_webhooks: secret resolver is not wired")
	}
	if !receiptMode || d.ingressCache == nil {
		secret, err := d.resolveSecret(ctx, namespace, secretName, packInstallID)
		return secret, false, err
	}
	return d.ingressCache.resolveSecret(ctx, d.resolveSecret, namespace, secretName, packInstallID, webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint))
}

func (d *Dispatcher) refreshWebhookSecret(ctx context.Context, namespace, secretName, packInstallID string, ackDropEndpoint bool) (*webhooks.ResolvedWebhookSecret, error) {
	if d == nil || d.resolveSecret == nil || d.ingressCache == nil {
		return nil, fmt.Errorf("connector_webhooks: secret refresh is not wired")
	}
	return d.ingressCache.refreshSecret(ctx, d.resolveSecret, namespace, secretName, packInstallID, webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint))
}

func (d *Dispatcher) refreshWebhookPack(ctx context.Context, namespace string, ackDropEndpoint bool) (*connector_packstate.ConnectorPackRow, bool, error) {
	if d == nil || d.resolvePack == nil || d.ingressCache == nil {
		return nil, false, fmt.Errorf("connector_webhooks: pack refresh is not wired")
	}
	return d.ingressCache.refreshPack(ctx, d.resolvePack, namespace, webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint))
}

func (d *Dispatcher) resolveWebhookSignatureVerifier(ctx context.Context, namespace, packInstallID string, receiptMode, ackDropEndpoint bool) (connectorcapabilities.SignatureVerifierHandler, error) {
	if d == nil || !receiptMode || d.ingressCache == nil {
		return d.registry.ResolveSignatureVerifier(ctx, namespace, packInstallID)
	}
	return d.ingressCache.resolveVerifier(ctx, d.registry, namespace, packInstallID, webhookIngressSnapshotDeadlineContractFor(ackDropEndpoint))
}

func (d *Dispatcher) evictWebhookIngressSnapshot(namespace string) {
	if d == nil || d.ingressCache == nil {
		return
	}
	d.ingressCache.evict(namespace)
}

func (c *webhookIngressSnapshotCache) resolvePack(
	ctx context.Context,
	resolve func(context.Context, string) (*connector_packstate.ConnectorPackRow, bool, error),
	namespace string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
) (*connector_packstate.ConnectorPackRow, bool, error) {
	if resolve == nil {
		return nil, false, fmt.Errorf("connector_webhooks: pack resolver is not wired")
	}
	key := normalizeWebhookIngressPackCacheKey(namespace)
	now := c.now()
	c.mu.Lock()
	c.pruneExpiredPacksLocked(now)
	if entry, ok := c.packs[key]; ok {
		row := entry.row
		c.mu.Unlock()
		recordConnectorWebhookIngressSnapshotCache("pack", "hit")
		return &row, true, nil
	}
	c.mu.Unlock()

	recordConnectorWebhookIngressSnapshotCache("pack", "miss")
	singleflightResult, waitErr := c.load(ctx, webhookIngressPackCacheSingleflightKey(key, deadlineContract), func(loadCtx context.Context) (any, error) {
		now := c.now()
		c.mu.Lock()
		c.pruneExpiredPacksLocked(now)
		if entry, ok := c.packs[key]; ok {
			row := entry.row
			c.mu.Unlock()
			return webhookIngressPackResolveResult{row: &row, ok: true}, nil
		}
		observedEpoch, loadID := c.retainPackLoadEpochLocked(key)
		c.mu.Unlock()
		defer c.releasePackEpoch(key, observedEpoch)

		recordConnectorWebhookIngressSnapshotCache("pack", "load")
		row, ok, err := resolve(loadCtx, namespace)
		if err != nil || !ok || row == nil {
			return webhookIngressPackResolveResult{ok: ok}, err
		}
		entry := webhookIngressPackCacheEntry{row: *row, expiresAt: c.now().Add(c.ttl)}
		c.mu.Lock()
		if c.packEpoch[key] != observedEpoch || observedEpoch.latestLoadID != loadID {
			if current, exists := c.packs[key]; exists {
				copied := current.row
				c.mu.Unlock()
				return webhookIngressPackResolveResult{row: &copied, ok: true}, nil
			}
			c.mu.Unlock()
			return webhookIngressPackResolveResult{}, fmt.Errorf("connector_webhooks: pack snapshot invalidated during load")
		}
		c.rotatePackEpochLocked(key)
		c.deleteSecretsForNamespaceExceptInstallLocked(key.namespace, strings.TrimSpace(row.InstallID))
		c.packs[key] = entry
		c.mu.Unlock()
		copied := entry.row
		return webhookIngressPackResolveResult{row: &copied, ok: true}, nil
	})
	if waitErr != nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, waitErr
	}
	if singleflightResult.shared {
		recordConnectorWebhookIngressSnapshotCache("pack", "shared")
	}
	if singleflightResult.err != nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, singleflightResult.err
	}
	result, ok := singleflightResult.value.(webhookIngressPackResolveResult)
	if !ok {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, fmt.Errorf("connector_webhooks: pack cache returned unexpected value")
	}
	if !result.ok || result.row == nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "empty")
		return nil, false, nil
	}
	row := *result.row
	return &row, true, nil
}

func (c *webhookIngressSnapshotCache) refreshPack(
	ctx context.Context,
	resolve func(context.Context, string) (*connector_packstate.ConnectorPackRow, bool, error),
	namespace string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
) (*connector_packstate.ConnectorPackRow, bool, error) {
	if resolve == nil {
		return nil, false, fmt.Errorf("connector_webhooks: pack resolver is not wired")
	}
	key := normalizeWebhookIngressPackCacheKey(namespace)

	recordConnectorWebhookIngressSnapshotCache("pack", "refresh")
	singleflightResult, waitErr := c.load(ctx, webhookIngressPackRefreshSingleflightKey(key, deadlineContract), func(loadCtx context.Context) (any, error) {
		c.mu.Lock()
		c.pruneExpiredPacksLocked(c.now())
		observedEpoch, loadID := c.retainPackLoadEpochLocked(key)
		c.mu.Unlock()
		defer c.releasePackEpoch(key, observedEpoch)

		recordConnectorWebhookIngressSnapshotCache("pack", "load")
		row, ok, err := resolve(loadCtx, namespace)
		if err != nil || !ok || row == nil {
			return webhookIngressPackResolveResult{ok: ok}, err
		}
		now := c.now()
		entry := webhookIngressPackCacheEntry{
			row:               *row,
			expiresAt:         now.Add(c.ttl),
			guardRefreshAfter: now.Add(defaultWebhookIngressGuardRefreshCooldown),
		}
		c.mu.Lock()
		if c.packEpoch[key] != observedEpoch || observedEpoch.latestLoadID != loadID {
			if current, exists := c.packs[key]; exists {
				copied := current.row
				c.mu.Unlock()
				return webhookIngressPackResolveResult{row: &copied, ok: true}, nil
			}
			c.mu.Unlock()
			return webhookIngressPackResolveResult{}, fmt.Errorf("connector_webhooks: pack snapshot invalidated during refresh")
		}
		if current, exists := c.packs[key]; exists {
			entry.guardRefreshAfter = current.guardRefreshAfter
		}
		c.rotatePackEpochLocked(key)
		c.deleteSecretsForNamespaceExceptInstallLocked(key.namespace, strings.TrimSpace(entry.row.InstallID))
		c.packs[key] = entry
		c.mu.Unlock()
		copied := entry.row
		return webhookIngressPackResolveResult{row: &copied, ok: true}, nil
	})
	if waitErr != nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, waitErr
	}
	if singleflightResult.shared {
		recordConnectorWebhookIngressSnapshotCache("pack", "shared")
	}
	if singleflightResult.err != nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, singleflightResult.err
	}
	result, ok := singleflightResult.value.(webhookIngressPackResolveResult)
	if !ok {
		recordConnectorWebhookIngressSnapshotCache("pack", "error")
		return nil, false, fmt.Errorf("connector_webhooks: pack refresh returned unexpected value")
	}
	if !result.ok || result.row == nil {
		recordConnectorWebhookIngressSnapshotCache("pack", "empty")
		return nil, false, nil
	}
	row := *result.row
	return &row, true, nil
}

func (c *webhookIngressSnapshotCache) resolveVerifier(
	ctx context.Context,
	registry *connectorcapabilities.Registry,
	namespace, packInstallID string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
) (connectorcapabilities.SignatureVerifierHandler, error) {
	if registry == nil {
		return nil, connectorcapabilities.ErrGateNotBound
	}
	key := normalizeWebhookIngressVerifierCacheKey(namespace, packInstallID)

	recordConnectorWebhookIngressSnapshotCache("signature_verifier", "miss")
	singleflightResult, waitErr := c.load(ctx, webhookIngressVerifierCacheSingleflightKey(key, deadlineContract), func(loadCtx context.Context) (any, error) {
		recordConnectorWebhookIngressSnapshotCache("signature_verifier", "load")
		return registry.ResolveSignatureVerifier(loadCtx, namespace, packInstallID)
	})
	if waitErr != nil {
		recordConnectorWebhookIngressSnapshotCache("signature_verifier", "error")
		return nil, waitErr
	}
	if singleflightResult.shared {
		recordConnectorWebhookIngressSnapshotCache("signature_verifier", "shared")
	}
	if singleflightResult.err != nil {
		recordConnectorWebhookIngressSnapshotCache("signature_verifier", "error")
		return nil, singleflightResult.err
	}
	verifier, ok := singleflightResult.value.(connectorcapabilities.SignatureVerifierHandler)
	if !ok || verifier == nil {
		recordConnectorWebhookIngressSnapshotCache("signature_verifier", "error")
		return nil, connectorcapabilities.ErrCapabilityNotAvailable
	}
	return verifier, nil
}

func (c *webhookIngressSnapshotCache) resolveSecret(
	ctx context.Context,
	resolve func(context.Context, string, string, string) (*webhooks.ResolvedWebhookSecret, error),
	namespace, secretName, packInstallID string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
) (*webhooks.ResolvedWebhookSecret, bool, error) {
	if resolve == nil {
		return nil, false, fmt.Errorf("connector_webhooks: secret resolver is not wired")
	}
	key := normalizeWebhookIngressSecretCacheKey(namespace, secretName, packInstallID)
	now := c.now()
	c.mu.Lock()
	c.pruneExpiredSecretsLocked(now)
	if entry, ok := c.secrets[key]; ok {
		if now.Before(entry.expiresAt) {
			secret := cloneResolvedWebhookSecret(entry.secret)
			c.mu.Unlock()
			recordConnectorWebhookIngressSnapshotCache("secret", "hit")
			return &secret, true, nil
		}
		delete(c.secrets, key)
	}
	c.mu.Unlock()

	recordConnectorWebhookIngressSnapshotCache("secret", "miss")
	secret, err := c.loadSecret(ctx, resolve, key, namespace, secretName, packInstallID, deadlineContract, "secret")
	return secret, false, err
}

func (c *webhookIngressSnapshotCache) refreshSecret(
	ctx context.Context,
	resolve func(context.Context, string, string, string) (*webhooks.ResolvedWebhookSecret, error),
	namespace, secretName, packInstallID string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
) (*webhooks.ResolvedWebhookSecret, error) {
	if resolve == nil {
		return nil, fmt.Errorf("connector_webhooks: secret resolver is not wired")
	}
	key := normalizeWebhookIngressSecretCacheKey(namespace, secretName, packInstallID)
	recordConnectorWebhookIngressSnapshotCache("secret", "refresh")
	return c.loadSecret(ctx, resolve, key, namespace, secretName, packInstallID, deadlineContract, "secret_refresh")
}

func (c *webhookIngressSnapshotCache) loadSecret(
	ctx context.Context,
	resolve func(context.Context, string, string, string) (*webhooks.ResolvedWebhookSecret, error),
	key webhookIngressSecretCacheKey,
	namespace, secretName, packInstallID string,
	deadlineContract webhookIngressSnapshotDeadlineContract,
	operation string,
) (*webhooks.ResolvedWebhookSecret, error) {
	// Refreshes can reach this path without first calling resolveSecret. Retire
	// expired plaintext before the resolver runs so a failed or slow refresh
	// cannot extend an entry's in-memory lifetime beyond the cache TTL.
	c.mu.Lock()
	c.pruneExpiredSecretsLocked(c.now())
	c.mu.Unlock()

	singleflightResult, waitErr := c.load(ctx, webhookIngressSecretCacheSingleflightKey(operation, key, deadlineContract), func(loadCtx context.Context) (any, error) {
		packKey := normalizeWebhookIngressPackCacheKey(key.namespace)
		c.mu.Lock()
		c.pruneExpiredPacksLocked(c.now())
		c.pruneExpiredSecretsLocked(c.now())
		observedPackEpoch := c.retainPackEpochLocked(packKey)
		observedSecretEpoch, loadID := c.retainSecretLoadEpochLocked(key)
		c.mu.Unlock()
		defer c.releaseSecretEpoch(key, observedSecretEpoch)
		defer c.releasePackEpoch(packKey, observedPackEpoch)

		recordConnectorWebhookIngressSnapshotCache("secret", "load")
		secret, err := resolve(loadCtx, namespace, secretName, packInstallID)
		if err != nil || secret == nil {
			return nil, err
		}
		entry := webhookIngressSecretCacheEntry{
			secret:    cloneResolvedWebhookSecret(*secret),
			expiresAt: c.now().Add(c.ttl),
		}
		c.mu.Lock()
		c.pruneExpiredSecretsLocked(c.now())
		if c.packEpoch[packKey] != observedPackEpoch ||
			c.secretEpoch[key] != observedSecretEpoch ||
			observedSecretEpoch.latestLoadID != loadID {
			if current, ok := c.secrets[key]; ok && c.now().Before(current.expiresAt) {
				copied := cloneResolvedWebhookSecret(current.secret)
				clear(entry.secret.Secret)
				c.mu.Unlock()
				return &copied, nil
			}
			clear(entry.secret.Secret)
			c.mu.Unlock()
			return nil, fmt.Errorf("connector_webhooks: secret snapshot invalidated during load")
		}
		c.deleteSecretsForNamespaceExceptInstallLocked(key.namespace, key.packInstallID)
		if previous, ok := c.secrets[key]; ok {
			clear(previous.secret.Secret)
		}
		c.rotateSecretEpochLocked(key)
		c.secrets[key] = entry
		copied := cloneResolvedWebhookSecret(entry.secret)
		c.mu.Unlock()
		return &copied, nil
	})
	if waitErr != nil {
		recordConnectorWebhookIngressSnapshotCache("secret", "error")
		return nil, waitErr
	}
	if singleflightResult.shared {
		recordConnectorWebhookIngressSnapshotCache("secret", "shared")
	}
	if singleflightResult.err != nil {
		recordConnectorWebhookIngressSnapshotCache("secret", "error")
		return nil, singleflightResult.err
	}
	secret, ok := singleflightResult.value.(*webhooks.ResolvedWebhookSecret)
	if !ok || secret == nil {
		recordConnectorWebhookIngressSnapshotCache("secret", "error")
		return nil, fmt.Errorf("connector_webhooks: secret cache returned unexpected value")
	}
	copied := cloneResolvedWebhookSecret(*secret)
	return &copied, nil
}

func cloneResolvedWebhookSecret(secret webhooks.ResolvedWebhookSecret) webhooks.ResolvedWebhookSecret {
	secret.Secret = append([]byte(nil), secret.Secret...)
	return secret
}

func (c *webhookIngressSnapshotCache) evict(namespace string) {
	namespace = strings.ToLower(strings.TrimSpace(namespace))
	key := normalizeWebhookIngressPackCacheKey(namespace)
	c.mu.Lock()
	delete(c.packEpoch, key)
	delete(c.packs, key)
	for key, entry := range c.secrets {
		if key.namespace == namespace {
			clear(entry.secret.Secret)
			delete(c.secretEpoch, key)
			delete(c.secrets, key)
		}
	}
	c.mu.Unlock()
	recordConnectorWebhookIngressSnapshotCache("snapshot", "evict")
}

func (c *webhookIngressSnapshotCache) beginReceiptGuardRefresh(namespace string) bool {
	key := normalizeWebhookIngressPackCacheKey(namespace)
	now := c.now()
	c.mu.Lock()
	defer c.mu.Unlock()
	c.pruneExpiredPacksLocked(now)
	entry, ok := c.packs[key]
	if !ok {
		return true
	}
	if now.Before(entry.guardRefreshAfter) {
		return false
	}
	entry.guardRefreshAfter = now.Add(defaultWebhookIngressGuardRefreshCooldown)
	c.packs[key] = entry
	return true
}

func (c *webhookIngressSnapshotCache) retainPackEpochLocked(key webhookIngressPackCacheKey) *webhookIngressEpoch {
	epoch := c.packEpoch[key]
	if epoch == nil {
		epoch = &webhookIngressEpoch{}
		c.packEpoch[key] = epoch
	}
	epoch.refs++
	return epoch
}

func (c *webhookIngressSnapshotCache) retainPackLoadEpochLocked(key webhookIngressPackCacheKey) (*webhookIngressEpoch, uint64) {
	epoch := c.retainPackEpochLocked(key)
	epoch.latestLoadID++
	return epoch, epoch.latestLoadID
}

func (c *webhookIngressSnapshotCache) releasePackEpoch(key webhookIngressPackCacheKey, epoch *webhookIngressEpoch) {
	if epoch == nil {
		return
	}
	c.mu.Lock()
	if epoch.refs > 0 {
		epoch.refs--
	}
	if epoch.refs == 0 && c.packEpoch[key] == epoch {
		if _, cached := c.packs[key]; !cached {
			delete(c.packEpoch, key)
		}
	}
	c.mu.Unlock()
}

func (c *webhookIngressSnapshotCache) rotatePackEpochLocked(key webhookIngressPackCacheKey) {
	c.packEpoch[key] = &webhookIngressEpoch{}
}

func (c *webhookIngressSnapshotCache) retainSecretEpochLocked(key webhookIngressSecretCacheKey) *webhookIngressEpoch {
	epoch := c.secretEpoch[key]
	if epoch == nil {
		epoch = &webhookIngressEpoch{}
		c.secretEpoch[key] = epoch
	}
	epoch.refs++
	return epoch
}

func (c *webhookIngressSnapshotCache) retainSecretLoadEpochLocked(key webhookIngressSecretCacheKey) (*webhookIngressEpoch, uint64) {
	epoch := c.retainSecretEpochLocked(key)
	epoch.latestLoadID++
	return epoch, epoch.latestLoadID
}

func (c *webhookIngressSnapshotCache) releaseSecretEpoch(key webhookIngressSecretCacheKey, epoch *webhookIngressEpoch) {
	if epoch == nil {
		return
	}
	c.mu.Lock()
	if epoch.refs > 0 {
		epoch.refs--
	}
	if epoch.refs == 0 && c.secretEpoch[key] == epoch {
		if _, cached := c.secrets[key]; !cached {
			delete(c.secretEpoch, key)
		}
	}
	c.mu.Unlock()
}

func (c *webhookIngressSnapshotCache) rotateSecretEpochLocked(key webhookIngressSecretCacheKey) {
	c.secretEpoch[key] = &webhookIngressEpoch{}
}

func (c *webhookIngressSnapshotCache) pruneExpiredPacksLocked(now time.Time) {
	for key, entry := range c.packs {
		if !now.Before(entry.expiresAt) {
			delete(c.packs, key)
			delete(c.packEpoch, key)
		}
	}
}

func (c *webhookIngressSnapshotCache) pruneExpiredSecretsLocked(now time.Time) {
	for key, entry := range c.secrets {
		if !now.Before(entry.expiresAt) {
			clear(entry.secret.Secret)
			delete(c.secretEpoch, key)
			delete(c.secrets, key)
		}
	}
}

func (c *webhookIngressSnapshotCache) deleteSecretsForNamespaceExceptInstallLocked(namespace, packInstallID string) {
	for key, entry := range c.secrets {
		if key.namespace == namespace && key.packInstallID != packInstallID {
			clear(entry.secret.Secret)
			delete(c.secretEpoch, key)
			delete(c.secrets, key)
		}
	}
}

func normalizeWebhookIngressPackCacheKey(namespace string) webhookIngressPackCacheKey {
	return webhookIngressPackCacheKey{namespace: strings.ToLower(strings.TrimSpace(namespace))}
}

func normalizeWebhookIngressVerifierCacheKey(namespace, packInstallID string) webhookIngressVerifierCacheKey {
	return webhookIngressVerifierCacheKey{
		namespace:     strings.ToLower(strings.TrimSpace(namespace)),
		packInstallID: strings.TrimSpace(packInstallID),
	}
}

func normalizeWebhookIngressSecretCacheKey(namespace, secretName, packInstallID string) webhookIngressSecretCacheKey {
	return webhookIngressSecretCacheKey{
		namespace:     strings.ToLower(strings.TrimSpace(namespace)),
		secretName:    strings.TrimSpace(secretName),
		packInstallID: strings.TrimSpace(packInstallID),
	}
}

func webhookIngressPackCacheSingleflightKey(key webhookIngressPackCacheKey, deadlineContract webhookIngressSnapshotDeadlineContract) string {
	return "pack:" + key.namespace + "\x00" + string(deadlineContract)
}

func webhookIngressPackRefreshSingleflightKey(key webhookIngressPackCacheKey, deadlineContract webhookIngressSnapshotDeadlineContract) string {
	return "pack_refresh:" + key.namespace + "\x00" + string(deadlineContract)
}

func webhookIngressVerifierCacheSingleflightKey(key webhookIngressVerifierCacheKey, deadlineContract webhookIngressSnapshotDeadlineContract) string {
	return "signature_verifier:" + key.namespace + "\x00" + key.packInstallID + "\x00" + string(deadlineContract)
}

func webhookIngressSecretCacheSingleflightKey(operation string, key webhookIngressSecretCacheKey, deadlineContract webhookIngressSnapshotDeadlineContract) string {
	return operation + ":" + key.namespace + "\x00" + key.secretName + "\x00" + key.packInstallID + "\x00" + string(deadlineContract)
}
