import { z } from "zod";

// === Enums ===

export const EventType = z.enum([
  "step.start",
  "step.complete",
  "decision",
  "agent.dispatch",
  "agent.result",
  "artifact.create",
  "validation",
  "error",
  "note",
]);

export const StepStatus = z.enum(["pass", "fail", "blocked"]);

export const ArtifactType = z.enum(["doc", "code", "config", "report", "seed", "asset"]);

export const ArtifactOperation = z.enum(["create", "update", "delete"]);

// === Conversation ===

export const ConversationMessage = z.object({
  role: z.enum(["user", "agent"]),
  message: z.string(),
});

// === Git context (auto-captured by CLI) ===

export const GitContext = z.object({
  branch: z.string(),
  commit: z.string(),
});

// === Event data payloads ===

export const StepStartData = z.object({
  skill: z.string(),
  context: z.record(z.string(), z.unknown()),
});

export const StepCompleteData = z.object({
  status: StepStatus,
  summary: z.string(),
  artifacts: z.array(z.string()),
});

export const DecisionData = z.object({
  question: z.string(),
  choice: z.string(),
  alternatives: z.array(z.string()),
  rationale: z.string(),
});

export const AgentDispatchData = z.object({
  agentName: z.string(),
  task: z.string(),
  inputs: z.record(z.string(), z.unknown()),
});

export const AgentResultData = z.object({
  agentName: z.string(),
  status: z.enum(["pass", "fail"]),
  outputs: z.record(z.string(), z.unknown()),
  duration_ms: z.number(),
});

export const ArtifactCreateData = z.object({
  path: z.string(),
  type: ArtifactType,
  operation: ArtifactOperation,
});

export const ValidationData = z.object({
  command: z.string(),
  status: z.enum(["pass", "fail"]),
  issues: z.array(z.string()),
});

export const ErrorData = z.object({
  message: z.string(),
  recoverable: z.boolean(),
});

export const NoteData = z.object({
  message: z.string(),
  tags: z.array(z.string()),
});

// === Flattened entry schemas ===
// Each variant is a complete object (no .and() intersection)
// to avoid Zod 4 issues with union + intersection.
//
// conversation field is recreated per schema to avoid sharing a .default()
// schema instance across multiple union members (Zod 4 limitation).

const convField = () => z.array(ConversationMessage).default([]);

// --- Entry schemas (stored in JSONL) ---

export const StepStartEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("step.start"),
  data: StepStartData,
});

export const StepCompleteEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("step.complete"),
  data: StepCompleteData,
});

export const DecisionEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("decision"),
  data: DecisionData,
});

export const AgentDispatchEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("agent.dispatch"),
  data: AgentDispatchData,
});

export const AgentResultEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("agent.result"),
  data: AgentResultData,
});

export const ArtifactCreateEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("artifact.create"),
  data: ArtifactCreateData,
});

export const ValidationEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("validation"),
  data: ValidationData,
});

export const ErrorEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("error"),
  data: ErrorData,
});

export const NoteEntry = z.object({
  v: z.literal(1),
  timestamp: z.string().datetime(),
  sessionId: z.string(),
  prompt: z.string(),
  git: GitContext,
  conversation: convField(),
  event: z.literal("note"),
  data: NoteData,
});

// z.union auto-detects the "event" discriminator in Zod 4
export const ProgressEntry = z.union([
  StepStartEntry,
  StepCompleteEntry,
  DecisionEntry,
  AgentDispatchEntry,
  AgentResultEntry,
  ArtifactCreateEntry,
  ValidationEntry,
  ErrorEntry,
  NoteEntry,
]);

// --- Input schemas (what skills pass to CLI, no timestamp/git) ---

export const StepStartInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("step.start"),
  data: StepStartData,
});

export const StepCompleteInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("step.complete"),
  data: StepCompleteData,
});

export const DecisionInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("decision"),
  data: DecisionData,
});

export const AgentDispatchInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("agent.dispatch"),
  data: AgentDispatchData,
});

export const AgentResultInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("agent.result"),
  data: AgentResultData,
});

export const ArtifactCreateInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("artifact.create"),
  data: ArtifactCreateData,
});

export const ValidationInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("validation"),
  data: ValidationData,
});

export const ErrorInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("error"),
  data: ErrorData,
});

export const NoteInput = z.object({
  v: z.literal(1),
  sessionId: z.string(),
  prompt: z.string(),
  conversation: convField(),
  event: z.literal("note"),
  data: NoteData,
});

export const ProgressInput = z.union([
  StepStartInput,
  StepCompleteInput,
  DecisionInput,
  AgentDispatchInput,
  AgentResultInput,
  ArtifactCreateInput,
  ValidationInput,
  ErrorInput,
  NoteInput,
]);

// === Inferred types ===

export type EventType = z.infer<typeof EventType>;
export type ConversationMessage = z.infer<typeof ConversationMessage>;
export type GitContext = z.infer<typeof GitContext>;
export type ProgressEntry = z.infer<typeof ProgressEntry>;
export type ProgressInput = z.infer<typeof ProgressInput>;
