// Package pathway implements Mem0-style versioned trace memory per
// ADR-004. Pathway memory is an append-only event log of opaque
// traces with Add / Update / Revise / Retire / History / Search
// operations. Persisted via JSONL (one event per line) with
// corruption recovery on load.
//
// Why this exists: agents need to remember what they tried and
// what worked. Mem0 is the lowest-common-denominator memory
// substrate; building on its surface means agent loops written
// against any Mem0-aware library work here. See feedback_meta_
// index_vision.md for the north-star learning-loop framing.
package pathway

import (
	"encoding/json"
	"errors"
)

// Trace is one entry in pathway memory. Content is opaque to the
// substrate — callers store whatever JSON shape they want; this
// layer just preserves and indexes it.
type Trace struct {
	UID            string          `json:"uid"`
	Content        json.RawMessage `json:"content"`
	PredecessorUID string          `json:"predecessor_uid,omitempty"`
	CreatedAtNs    int64           `json:"created_at_ns"`
	UpdatedAtNs    int64           `json:"updated_at_ns"`
	Retired        bool            `json:"retired"`
	ReplayCount    int             `json:"replay_count"`
	Tags           []string        `json:"tags,omitempty"`
}

// op is the wire-format kind tag for JSONL persistence. Internal
// to the package — operations exposed publicly are method calls
// on Store; the JSONL form is its own concern.
type op string

const (
	opAdd     op = "add"
	opUpdate  op = "update"
	opRevise  op = "revise"
	opRetire  op = "retire"
	opReplay  op = "replay"
)

// event is one line of the JSONL log. Trace is included for ops
// that introduce or replace a trace; UID alone suffices for retire
// and replay; Content alone suffices for update (reuses the
// existing trace's UID via the UID field).
type event struct {
	Op      op              `json:"op"`
	Trace   *Trace          `json:"trace,omitempty"`
	UID     string          `json:"uid,omitempty"`
	Content json.RawMessage `json:"content,omitempty"`
}

// Errors surfaced to callers. Sentinel-based so HTTP handlers (when
// cmd/pathwayd lands) can map to status codes via errors.Is.
var (
	ErrNotFound        = errors.New("pathway: trace not found")
	ErrAlreadyExists   = errors.New("pathway: trace already exists")
	ErrPredecessorMissing = errors.New("pathway: predecessor trace missing")
	ErrCycle           = errors.New("pathway: history cycle detected")
	ErrEmptyUID        = errors.New("pathway: empty uid")
	ErrInvalidContent  = errors.New("pathway: invalid content")
)

// SearchFilter narrows a Search to matching traces. Empty filter
// returns everything (excluding retired; flip IncludeRetired to
// override). All set fields are AND-combined.
type SearchFilter struct {
	// Tag returns traces whose Tags slice contains this string.
	Tag string

	// ContentContains returns traces whose Content contains this
	// substring (treats Content as raw bytes; caller's contract
	// for whether that's meaningful).
	ContentContains string

	// CreatedAfterNs returns traces with CreatedAtNs >= this value.
	CreatedAfterNs int64

	// CreatedBeforeNs returns traces with CreatedAtNs <= this value.
	// Zero = no upper bound.
	CreatedBeforeNs int64

	// IncludeRetired flips the default "exclude retired" behavior.
	IncludeRetired bool
}
