package files

import (
	"strings"
	"sync"
)

// HrefRewriteField names a (objectApiName, fieldApiName) pair whose value can
// be decorated by an installed record-read decorator. Platform code declares
// zero pairs by default; product/distribution or transitional import wiring
// supplies the pairs for its own record decoration behavior.
type HrefRewriteField struct {
	ParentApiName string
	FieldApiName  string
}

var (
	hrefRewriteMu       sync.RWMutex
	hrefRewriteRegistry []HrefRewriteField
)

// RegisterHrefFields appends (object, field) pairs to the rewrite registry.
// Duplicate pairs are deduped so repeated test or composition setup is safe.
//
// This registry remains transitional until #2258 PR 3 moves field-pair
// ownership into pack/dialect metadata. The generic files package owns only the
// registration list, not any product-specific parser or lookup policy.
func RegisterHrefFields(fields ...HrefRewriteField) {
	hrefRewriteMu.Lock()
	defer hrefRewriteMu.Unlock()
	seen := make(map[hrefRewriteFieldKey]struct{}, len(hrefRewriteRegistry)+len(fields))
	for _, f := range hrefRewriteRegistry {
		seen[hrefRewriteKey(f)] = struct{}{}
	}
	for _, f := range NormalizeHrefRewriteFields(fields) {
		key := hrefRewriteKey(f)
		if _, dup := seen[key]; dup {
			continue
		}
		seen[key] = struct{}{}
		hrefRewriteRegistry = append(hrefRewriteRegistry, f)
	}
}

// NormalizeHrefRewriteFields trims and dedupes field pairs while preserving the
// first declaration's casing.
func NormalizeHrefRewriteFields(fields []HrefRewriteField) []HrefRewriteField {
	seen := make(map[hrefRewriteFieldKey]struct{}, len(fields))
	out := make([]HrefRewriteField, 0, len(fields))
	for _, f := range fields {
		f.ParentApiName = strings.TrimSpace(f.ParentApiName)
		f.FieldApiName = strings.TrimSpace(f.FieldApiName)
		if f.ParentApiName == "" || f.FieldApiName == "" {
			continue
		}
		key := hrefRewriteKey(f)
		if _, dup := seen[key]; dup {
			continue
		}
		seen[key] = struct{}{}
		out = append(out, f)
	}
	return out
}

type hrefRewriteFieldKey struct {
	parent string
	field  string
}

func hrefRewriteKey(f HrefRewriteField) hrefRewriteFieldKey {
	return hrefRewriteFieldKey{
		parent: strings.ToLower(strings.TrimSpace(f.ParentApiName)),
		field:  strings.ToLower(strings.TrimSpace(f.FieldApiName)),
	}
}

// ClearHrefFields clears the process-local registry before rebuilding it from
// installed runtime pack declarations.
func ClearHrefFields() {
	hrefRewriteMu.Lock()
	hrefRewriteRegistry = nil
	hrefRewriteMu.Unlock()
}

// ResetHrefFieldsForTest clears the registry for isolated tests.
func ResetHrefFieldsForTest() { ClearHrefFields() }

func snapshotHrefFields() []HrefRewriteField {
	hrefRewriteMu.RLock()
	defer hrefRewriteMu.RUnlock()
	if len(hrefRewriteRegistry) == 0 {
		return nil
	}
	out := make([]HrefRewriteField, len(hrefRewriteRegistry))
	copy(out, hrefRewriteRegistry)
	return out
}

// FieldsToRewriteForObject returns field API names registered for the given
// parent object, or nil when the object has no registered fields.
func FieldsToRewriteForObject(objectApiName string) []string {
	var fields []string
	objectApiName = strings.TrimSpace(objectApiName)
	for _, f := range snapshotHrefFields() {
		if strings.EqualFold(strings.TrimSpace(f.ParentApiName), objectApiName) {
			fields = append(fields, f.FieldApiName)
		}
	}
	return fields
}
