import type { Expr } from "./ast";
import type { Val } from "./eval/values";
import type { DistVal } from "./eval/dist";
import type { Evidence } from "./provenance/evidence";

/**
 * Obligation types for governing program transformations.
 * These must be discharged before a commit can succeed.
 */
export type Obligation =
  | { tag: "OblTests"; tests: Expr[]; envRef: string }
  | { tag: "OblIdempotent"; f: Expr; domain?: Val }
  | { tag: "OblNoMatch"; pattern: Expr; scope: "output" | "all" }
  | { tag: "OblEqExt"; original: Expr; candidate: Expr; tests: Expr[]; envRef: string }
  | { tag: "OblShellCheck"; command: string; expectedExit: number; description?: string }
  | { tag: "OblOracleVerify"; prompt: string; schema?: string; minConfidence?: number };

/**
 * Meaning is a VALUE in Omega.
 * We store "residual/rewrite" as Val so callers can represent them as Syntax
 * values or as quoted AST data.
 */
export type MeaningVal = {
  tag: "Meaning";
  denotation?: Val | DistVal;
  residual?: Val;
  rewrite?: Val;
  invariants?: Val;
  effects?: Val;
  cost?: Val;
  paths?: Val;
  deps?: Val;
  memo?: Val;
  obligation?: Val;
  obligations?: Obligation[];
  evidence?: Evidence[];
  confidence?: number;
  trace?: Val | RewriteStep[];
  adoptEnvRef?: string;
  adoptStateRef?: string;
};

/**
 * Rewrite trace step for debugging and audit.
 */
export type RewriteStep = {
  rule: string;
  before: Val;
  after: Val;
  position?: string;
};

export function meaning(partial: Omit<MeaningVal, "tag">): MeaningVal {
  return { tag: "Meaning", ...partial };
}

export function isMeaning(v: Val): v is MeaningVal {
  return typeof v === "object" && v !== null && (v as any).tag === "Meaning";
}
