// Package autonumber implements metadata-driven identifier assignment for NexusCRM.
//
// This package is the v2 autonumber engine described in
// docs/design/autonumber-engine-v2.md. It owns format parsing, counter
// reservation, cross-record token resolution, and rendering of assigned
// values for INSERTs driven by `_System_Field.auto_number_format`.
//
// The types defined in this file mirror the data model described in PRD §4
// (schema) and §6 (format grammar). Implementation details live in
// engine.go / parser.go / renderer.go / canonicalize.go and are filled in
// in a later wave; at this point the types are stable enough for tests to
// compile against.
package autonumber

// Scope values for `_System_Field.auto_number_scope` (PRD §4.1).
//
// v3 permits three scopes:
//   - `global`     — monotonic forever
//   - `per_day`    — resets per UTC calendar day (time-derived scope key)
//   - `per_prefix` — resets per distinct rendered non-counter portion of
//     the format string (data-derived scope key); lets a
//     single field own independent sequences per country
//     / record type / date partition without engine-side
//     hardcoding. Mirrors the Apex trigger convention
//     used by NexusCRM for Quote.Name / Order.Name /
//     Contract.Name and the IBG-B- prefix of
//     Account.Account_ID__c (Apex: `YYMMDD + NN` per
//     distinct literal prefix).
const (
	// ScopeGlobal — counter is monotonic across the entire field lifetime.
	ScopeGlobal = "global"
	// ScopePerDay — counter resets per UTC calendar day, keyed by
	// `deriveScopeKey(assignedAt)` == `YYYY-MM-DD`.
	ScopePerDay = "per_day"
	// ScopePerPrefix — counter is partitioned by the rendered non-counter
	// portion of the format (see RenderScopePrefix). Each distinct prefix
	// owns an independent sequence, which is how NexusCRM's Apex triggers
	// historically generated Quote/Order/Contract Name numbers.
	ScopePerPrefix = "per_prefix"
)

// TokenKind enumerates the classes of format tokens produced by Parse
// (PRD §6.1). The BNF has five terminal token kinds plus the literal
// interleavings between them.
type TokenKind int

const (
	// TokenKindLiteral — raw characters between recognized tokens
	// (PRD §6.1 `literal`).
	TokenKindLiteral TokenKind = iota
	// TokenKindCounter — `{0+}` sequence; the `Width` field on Token
	// carries the count of zeros (PRD §6.1 `counter_token`; §6.2 rules 1-2).
	TokenKindCounter
	// TokenKindDate — `{YYYY}`, `{YY}`, `{MM}`, `{DD}`
	// (PRD §6.1 `date_token`).
	TokenKindDate
	// TokenKindField — generic cross-record token
	// `{<Object>.<Field>}` (PRD §6.1 `cross_record_token`, §3.5).
	TokenKindField
	// TokenKindRecordType — `{RecordType.<Field>}` taxonomy token
	// (PRD §6.1 `taxonomy_token`; parsed first, more specific than the
	// general cross-record form).
	TokenKindRecordType
)

// Token is one element of a parsed FormatSpec. Only the fields relevant
// to the kind are populated; the rest are zero-valued.
type Token struct {
	// Kind is the discriminator.
	Kind TokenKind
	// Lit carries the raw literal bytes for TokenKindLiteral.
	Lit string
	// Width carries the counter width (number of `0` characters) for
	// TokenKindCounter. PRD §6.2 rule 2: 1..18.
	Width int
	// DateName carries the raw date token name (`YYYY`/`YY`/`MM`/`DD`)
	// for TokenKindDate.
	DateName string
	// Object carries the object API name portion of a
	// TokenKindField / TokenKindRecordType.
	Object string
	// Field carries the field API name portion of a
	// TokenKindField / TokenKindRecordType.
	Field string
	// RefKey is the canonical key used by the renderer to look up the
	// resolved cross-record value (typically `{Object.Field}` verbatim).
	RefKey string
}

// FormatSpec is the parsed, validated representation of an
// `auto_number_format` string. It is cached once per distinct format
// string by the engine (PRD §5.4).
type FormatSpec struct {
	// Raw is the original format string as stored in
	// `_System_Field.auto_number_format`.
	Raw string
	// Tokens is the full ordered token stream, literals included.
	Tokens []Token
	// CounterWidth is the width of the single counter token (PRD §6.2
	// rule 1: exactly one). Zero if no counter token (parser rejects).
	CounterWidth int
}

// FormatSpec convenience helpers are defined alongside Parse in
// parser.go (HasDateToken, RequiresRecordType). They are needed by
// validation rule 9 (per_day scope requires a date token) and rule 7
// (taxonomy token requires RecordTypeId on the source object),
// respectively (PRD §6.2).

// CrossRecordStep is one hop in a cross-record resolution chain
// (`fkChains` entry; PRD §4.1 JSON shape).
type CrossRecordStep struct {
	// FK is the lookup field on the current object whose
	// `ReferenceTo` points at TargetObject.
	FK string `json:"fk"`
	// TargetField is the field to read on the resolved row
	// (terminal hop reads a stored scalar per §6.2 rule 8).
	TargetField string `json:"targetField"`
	// TargetObject is the object API name the FK points at.
	TargetObject string `json:"targetObject"`
}

// CrossRecordRef is the pre-parsed descriptor stored in
// `_System_Field.auto_number_token_refs` (PRD §4.1). One entry per
// cross-record token in the format string.
type CrossRecordRef struct {
	// DirectField is an optional fast-path: a denormalized source
	// column on the same record that holds the target value without a
	// join. See `compound_autonumber_listener.go:86`.
	DirectField string `json:"directField,omitempty"`
	// FkChains is the ordered list of resolution paths. The first
	// chain whose walk yields a non-empty value wins (§3.5).
	FkChains [][]CrossRecordStep `json:"fkChains"`
	// ReadStrategy is one of `caller_txn` (default) or `fresh_read`
	// (PRD §3.5 P1-R2-A).
	ReadStrategy string `json:"readStrategy"`
	// TargetField is the terminal field API name the token renders.
	TargetField string `json:"targetField"`
	// TargetObject is the terminal object API name.
	TargetObject string `json:"targetObject"`
	// TokenLiteral is the exact token as it appears in the format
	// string, e.g. `{Account.BillingCountryCode}`.
	TokenLiteral string `json:"tokenLiteral"`
}

// Rule is the engine's cached metadata view of a single
// `_System_Field` row with autonumber configured. Mirrors the six
// new columns added in PRD §4.1 plus the owning FieldID.
type Rule struct {
	// FieldID is `_System_Field.Id`.
	FieldID string
	// ObjectAPIName is the owning `_System_Object.ApiName` (the
	// physical table name under NexusCRM's naming convention).
	// Needed so the engine can run a live-data scan against the
	// correct table when lazy-initializing a per_prefix counter row
	// — see reserveInput.liveMaxFn.
	ObjectAPIName string
	// FieldAPIName is `_System_Field.ApiName` (the physical column
	// name). Paired with ObjectAPIName for the same live-scan use
	// case.
	FieldAPIName string
	// Format is the raw `auto_number_format` string.
	Format string
	// Start is `auto_number_start` (BIGINT, default 1).
	Start int64
	// Scope is one of ScopeGlobal / ScopePerDay / ScopePerPrefix.
	Scope string
	// DateSrc is `auto_number_date_src`; v3 fixes this at
	// `assigned_at`.
	DateSrc string
	// OnChange is `auto_number_on_change`; v3 runtime honors only
	// `keep_existing`.
	OnChange string
	// TokenRefs is the decoded `auto_number_token_refs` JSON.
	TokenRefs []CrossRecordRef
	// Spec is the parse result of Format. Populated on metadata cache
	// load; nil until Parse has run.
	Spec *FormatSpec
}

// (BootstrapSeed removed in Wave 2 — fixpack F6 renamed the engine
// bootstrap API to Engine.BootstrapField(rule Rule) / Engine.
// SeedFieldCounter(fieldID string) with the rule looked up from the
// MetadataProvider. Callers no longer construct a bundle struct.)
