package fieldprovenance

import (
	"sync/atomic"

	"github.com/nexuscrm/shared/pkg/constants"
)

// Package-level default classifier.
//
// The intended lifecycle is:
//   1. Bootstrap parses the L1 manifests (system_tables.json + standard_
//      objects_spec.json + tenant_objects_spec.json) and the platform
//      standard-field template, translates them into []ObjectDeclaration,
//      calls BuildClassifier(...), and hands the result to SetDefault.
//   2. All call sites (ComputeIntrinsic Layer 1d/1e, describe emitters,
//      persistence gates) consult ClassifySource / ClassifyCompound at the
//      package level; those delegate to the default classifier.
//   3. SetDefault should be called exactly once, early in startup. No writes
//      after init means the post-init classifier is safe for concurrent
//      reads without locks.
//
// Uses atomic.Pointer so a nil default doesn't crash callers during
// pre-init code paths (returns the "nothing declared" answer, i.e.
// FieldSourceDiscovered for Source and (false, nil) for Compound). This
// preserves a safe fallback during cold-start ordering; production callers
// should still ensure SetDefault ran before serving.

var defaultClassifier atomic.Pointer[Classifier]

// SetDefault installs c as the package-level classifier. Subsequent calls
// to the package-level ClassifySource / ClassifyCompound delegate to c.
// Safe to call more than once (e.g. in tests); callers should ensure the
// swap happens at a quiescent moment (no concurrent classify calls).
func SetDefault(c *Classifier) {
	defaultClassifier.Store(c)
}

// Default returns the currently installed classifier, or nil if SetDefault
// has never been called. Prefer the package-level ClassifySource /
// ClassifyCompound functions for regular use; Default is exposed for
// callers that need to wire the classifier explicitly (e.g. constructing
// a test double in place of the global).
func Default() *Classifier {
	return defaultClassifier.Load()
}

// ClassifySource delegates to the package-level default classifier. Returns
// FieldSourceDiscovered when no default has been installed (defensive —
// SetDefault must run before any real consumer calls this in production).
func ClassifySource(objectAPIName, fieldAPIName string) string {
	c := Default()
	if c == nil {
		return constants.FieldSourceDiscovered
	}
	return c.ClassifySource(objectAPIName, fieldAPIName)
}

// ClassifyCompound delegates to the package-level default classifier.
// Returns (false, nil) when no default has been installed.
func ClassifyCompound(objectAPIName, fieldAPIName string) (isCompound bool, composedFrom []string) {
	c := Default()
	if c == nil {
		return false, nil
	}
	return c.ClassifyCompound(objectAPIName, fieldAPIName)
}

// ClassifyCompoundMember delegates to the package-level default classifier.
// Returns empty strings when no default has been installed.
func ClassifyCompoundMember(objectAPIName, fieldAPIName string) (compoundFieldName, compoundComponentRole string) {
	c := Default()
	if c == nil {
		return "", ""
	}
	return c.ClassifyCompoundMember(objectAPIName, fieldAPIName)
}
