import { ImportanceLevel, PluginConfig } from './types.js';
import { LocalLlmClient } from './local-llm.js';
import { FallbackLlmClient } from './fallback-llm.js';
import './model-registry.js';

/**
 * Extraction Judge — LLM-as-judge fact-worthiness gate (issue #376).
 *
 * Evaluates extracted facts against a durability rubric before they are
 * persisted. Facts that are unlikely to be useful 30+ days from now or
 * across sessions are rejected (or shadow-logged depending on config).
 *
 * Design constraints:
 *   - Corrections and principles are auto-approved (safety bypass).
 *   - Critical-importance facts are auto-approved.
 *   - Batches respect extractionJudgeBatchSize.
 *   - Content-hash caching avoids redundant LLM calls.
 *   - Performance budget: <= 1.5s per batch.
 */

interface JudgeCandidate {
    text: string;
    category: string;
    confidence: number;
    tags?: string[];
    /** Local importance level, set by caller before judging. */
    importanceLevel?: ImportanceLevel;
}
/**
 * Verdict kinds (issue #562, PR 1).
 *
 * - `"accept"`: fact is durable, persist it.
 * - `"reject"`: fact is not durable, drop it.
 * - `"defer"`: fact is ambiguous; push it back into the buffer for another
 *   pass with fresh context. Inspired by MemReader (arxiv 2604.07877).
 *
 * PR 1 only introduces the type. No emit path produces `"defer"` yet — the
 * defer-capable prompt, buffer re-routing, telemetry, and GRPO data
 * collection are landing in PRs 2, 3, and 4 respectively.
 */
type JudgeVerdictKind = "accept" | "reject" | "defer";
/**
 * Judge verdict shape.
 *
 * Back-compat note: `kind` is optional. Verdicts serialized before PR 1
 * (both in-memory cache entries and any persisted caches) only carry
 * `{ durable, reason }`. Downstream consumers must either read `durable`
 * directly, or use {@link getVerdictKind} / {@link isDurableVerdict} which
 * gracefully fall back to the boolean when `kind` is missing, and ignore
 * unknown future `kind` values rather than crashing.
 */
interface JudgeVerdict {
    /**
     * True iff the fact should be persisted. For `"defer"` verdicts this is
     * `false` — a deferred fact is not (yet) persisted, so callers that only
     * look at `durable` will treat defer as "skip this turn", which matches
     * the pre-PR-1 fail-closed behavior for non-accepted verdicts.
     */
    durable: boolean;
    reason: string;
    /**
     * Optional explicit verdict kind. Added in PR 1 of issue #562. Legacy
     * verdicts (including cache entries produced before this field existed)
     * do not set `kind`; use {@link getVerdictKind} to read this safely.
     */
    kind?: JudgeVerdictKind;
}
/**
 * Resolve a verdict's effective kind.
 *
 * - If `kind` is explicitly set to one of the known values, return it.
 * - If `kind` is absent, infer from `durable` (back-compat with pre-PR-1
 *   cache entries and emit paths that have not been updated yet).
 * - If `kind` is set to an unrecognised value (forward-compat, e.g. a
 *   future cache entry loaded by an older build), fall back to `durable`
 *   so we never crash on unknown strings.
 */
declare function getVerdictKind(verdict: JudgeVerdict): JudgeVerdictKind;
/**
 * Type guard: returns `true` only for verdicts that should be persisted.
 * Treats both `"reject"` and `"defer"` as "not durable" — defer means the
 * caller should re-evaluate later, not write now.
 */
declare function isDurableVerdict(verdict: JudgeVerdict): boolean;
/**
 * Validate a cache entry loaded from persistence / another process.
 *
 * Strict: accepts legacy `{ durable, reason }` entries and new entries
 * whose `kind` is one of the three known `JudgeVerdictKind` values.
 * Rejects structurally wrong types and unknown `kind` strings so the
 * type-guard narrowing is sound — callers that receive
 * `value is JudgeVerdict` can safely treat `kind` as the declared
 * union.
 *
 * Forward-compat is handled by {@link normalizeCachedVerdict}, which
 * drops unknown `kind` strings before validation so a newer build's
 * cache entry still loads instead of being rejected.
 */
declare function isValidCachedVerdict(value: unknown): value is JudgeVerdict;
/**
 * Forward-compatible cache-entry loader.
 *
 * Drops unknown `kind` strings to `undefined` (so `getVerdictKind` can
 * fall back to `durable`), then validates structurally. Non-string
 * `kind` values are still treated as structural violations and rejected.
 * Returns the sanitised verdict, or `null` when the entry is structurally
 * unusable.
 */
declare function normalizeCachedVerdict(value: unknown): JudgeVerdict | null;
interface JudgeBatchResult {
    verdicts: Map<number, JudgeVerdict>;
    /** Number of verdicts served from cache. */
    cached: number;
    /** Number of verdicts produced by an LLM call. */
    judged: number;
    /** Total wall-clock time in milliseconds. */
    elapsed: number;
    /**
     * Number of verdicts in this batch that resolved to `"defer"` (issue #562,
     * PR 2). Callers can use this to decide whether to retain buffer turns for
     * the next extraction pass.
     */
    deferred: number;
    /**
     * Number of defers that were forcibly converted to `"reject"` because the
     * same candidate text had already been deferred at least
     * `extractionJudgeMaxDeferrals` times. Rolled out of `deferred` — a
     * candidate counted here is *not* also in `deferred`.
     */
    deferredCappedToReject: number;
}
/**
 * Per-verdict observation emitted by `judgeFactDurability` when an
 * `onVerdict` callback is supplied (issue #562, PR 3). Used to wire the
 * observation ledger / telemetry stream without coupling the judge module
 * directly to filesystem I/O. One event is emitted for every resolved
 * verdict, including auto-approved and cache-hit paths.
 */
interface JudgeVerdictObservation {
    verdict: JudgeVerdict;
    /** The original `JudgeCandidate` passed in (same reference). */
    candidate: JudgeCandidate;
    /** SHA-256 of `text\0category`, same key the cache/deferCounter use. */
    contentHash: string;
    /** Verdict resolution path. Useful for debugging + dashboards. */
    source: "auto-approve" | "cache" | "llm" | "llm-cap-rejected" | "fail-open";
    /**
     * How many times this candidate had already been deferred before this
     * verdict resolved. 0 when the candidate had never been deferred.
     */
    priorDeferrals: number;
    /**
     * Milliseconds from batch start to now. Shared across verdicts emitted in
     * the same batch.
     */
    elapsedMs: number;
}
/**
 * Deterministic gate for extracted `procedure` memories: ≥2 steps with non-empty
 * intents and explicit trigger wording in title and/or steps.
 */
declare function validateProcedureExtraction(input: {
    content: string;
    procedureSteps?: unknown;
}): JudgeVerdict;
/**
 * Evaluate a batch of candidate facts for durability.
 *
 * Auto-approves corrections, principles, and critical-importance facts.
 * Remaining candidates are batched (up to extractionJudgeBatchSize),
 * checked against an in-memory content-hash cache, and sent to the LLM
 * for verdict.
 */
declare function judgeFactDurability(candidates: JudgeCandidate[], config: PluginConfig, localLlm: LocalLlmClient | null, fallbackLlm: FallbackLlmClient | null, cache?: Map<string, JudgeVerdict>, deferCounts?: Map<string, number>, onVerdict?: (observation: JudgeVerdictObservation) => void): Promise<JudgeBatchResult>;
/** Clear the in-memory default verdict cache. Primarily for tests. */
declare function clearVerdictCache(): void;
/** Return the current default verdict cache size. Primarily for tests. */
declare function verdictCacheSize(): number;
/** Create a new per-instance verdict cache. Orchestrators should hold one. */
declare function createVerdictCache(): Map<string, JudgeVerdict>;
/**
 * Create a new per-instance defer-counter map. Orchestrators should hold one
 * alongside their verdict cache so defer counts survive across extraction
 * passes within a single orchestrator but do not leak across orchestrators.
 */
declare function createDeferCountMap(): Map<string, number>;

export { type JudgeBatchResult, type JudgeCandidate, type JudgeVerdict, type JudgeVerdictKind, type JudgeVerdictObservation, clearVerdictCache, createDeferCountMap, createVerdictCache, getVerdictKind, isDurableVerdict, isValidCachedVerdict, judgeFactDurability, normalizeCachedVerdict, validateProcedureExtraction, verdictCacheSize };
