package litigationplanner

import (
	"context"

	"github.com/google/uuid"
)

// Catalog supplies proceeding-type metadata + rules for the calculator.
//
// Implementations:
//   - paliad: reads paliad.deadline_rules + paliad.proceeding_types,
//     filtered to lifecycle_state='published' AND is_active=true.
//     ProjectHint scopes future per-project rule merges.
//   - embedded/upc (Slice C): in-memory map keyed by code, populated
//     once at init from the embedded JSON snapshot.
//
// All methods return ErrUnknownProceedingType / ErrUnknownRule when the
// caller asks for a code/id that doesn't exist in the catalog.
type Catalog interface {
	// LoadProceeding returns the proceeding-type metadata + the full
	// rule list (sorted by sequence_order). Caller passes the user-
	// facing proceeding code (e.g. "upc.inf.cfi"). The hint scopes a
	// future per-project rule merge — implementations that don't
	// support projects ignore it.
	LoadProceeding(ctx context.Context, code string, hint ProjectHint) (*ProceedingType, []Rule, error)

	// LoadProceedingByID is the resolver used by CalculateRule when it
	// has a rule + needs the rule's parent proceeding metadata.
	LoadProceedingByID(ctx context.Context, id int) (*ProceedingType, error)

	// LoadRuleByID resolves a rule UUID to the rule row. Used by
	// CalculateRule when the caller supplies CalcRuleParams.RuleID.
	LoadRuleByID(ctx context.Context, ruleID string) (*Rule, error)

	// LoadRuleByCode resolves a rule by (proceedingCode, submissionCode)
	// + returns the parent proceeding for use in the response identity.
	// Used by CalculateRule when the caller supplies the (code, local)
	// pair from a concept-card pill.
	LoadRuleByCode(ctx context.Context, proceedingCode, submissionCode string) (*Rule, *ProceedingType, error)

	// LoadRulesByTriggerEvent lists Pipeline-C trigger-event-rooted
	// rules (rules whose trigger_event_id matches). Used by
	// EventDeadlineService → Calculate via CalcOptions.TriggerEventIDFilter.
	LoadRulesByTriggerEvent(ctx context.Context, triggerEventID int64) ([]Rule, error)

	// LoadTriggerEventsByIDs bulk-loads paliad.trigger_events rows
	// for the conditional-label override (t-paliad-294 /
	// m/paliad#126). Returns a map keyed by event id; missing ids
	// are simply absent (caller treats absence as "no override").
	// Empty input returns an empty map without a DB roundtrip.
	LoadTriggerEventsByIDs(ctx context.Context, ids []int64) (map[int64]TriggerEvent, error)

	// LookupEvents returns deadline rules matching any subset of the
	// requested axes, at the requested sequence depth (Slice B2,
	// m/paliad#124 §18.2). Used by the Determinator cascade, the
	// scenarios surface (Slice D), and any future "show me events
	// matching X" query. Empty result is NOT an error.
	//
	// Implementations must respect the catalog's "published + active"
	// rule gate (rules with lifecycle_state='draft' or is_active=false
	// must NEVER appear in the result). Sort order is
	// (proceeding_type_id, sequence_order) so the frontend can render
	// without re-sorting.
	LookupEvents(ctx context.Context, axes EventLookupAxes, depth EventLookupDepth) ([]EventMatch, error)

	// LoadScenarios lists scenarios visible to the caller, narrowed by
	// the filter (Slice D, m/paliad#124 §5). Returns an empty slice
	// (NOT an error) when no scenarios match. paliad-side impl applies
	// RLS (paliad.can_see_project for project-scoped, created_by for
	// abstract); snapshot-backed catalogs return an empty list.
	LoadScenarios(ctx context.Context, filter ScenarioFilter) ([]Scenario, error)

	// MatchScenario returns the scenario with the given id, or
	// ErrUnknownScenario if not found / not visible. The engine adapter
	// (CalculateFromScenario) calls this to fetch a scenario by id and
	// then unpacks its spec via ParseSpec.
	MatchScenario(ctx context.Context, id uuid.UUID) (*Scenario, error)
}
