import { z } from 'zod';
import { approvalOnRejectSchema } from './dag-node.js';

export const WorkflowRunStatusSchema = z.enum([
  'pending',
  'running',
  'paused',
  'completed',
  'failed',
  'cancelled',
]);

export type WorkflowRunStatus = z.infer<typeof WorkflowRunStatusSchema>;

/** Statuses that indicate the run has finished (no further transitions). */
export const TERMINAL_WORKFLOW_STATUSES = WorkflowRunStatusSchema.options.filter(
  (s): s is 'completed' | 'failed' | 'cancelled' =>
    s === 'completed' || s === 'failed' || s === 'cancelled',
);

/** Statuses from which a run can be resumed. */
export const RESUMABLE_WORKFLOW_STATUSES = WorkflowRunStatusSchema.options.filter(
  (s): s is 'paused' | 'failed' =>
    s === 'paused' || s === 'failed',
);

export const NodeStateSchema = z.enum([
  'pending',
  'running',
  'completed',
  'failed',
  'skipped',
]);

export type NodeState = z.infer<typeof NodeStateSchema>;

// NOTE: NodeOutput type is in node-output.ts — re-exported via schema/index.ts

export const ApprovalContextSchema = z.object({
  /** Discriminator for the approval type. */
  type: z.literal('approval'),

  /** The node that is waiting for approval. */
  nodeId: z.string().min(1, 'nodeId must not be empty'),

  /** Message shown to the approver. */
  message: z.string().min(1, 'approval message must not be empty'),

  /** Whether the approver's response should be captured. */
  capture_response: z.boolean().default(false),

  /** What to do when the approval is rejected. */
  on_reject: approvalOnRejectSchema.optional(),
});

export type ApprovalContext = z.infer<typeof ApprovalContextSchema>;

export const WorkflowRunSchema = z.object({
  /** Unique run identifier. */
  id: z.string().min(1, 'run id must not be empty'),

  /** Name of the workflow being run. */
  workflow_name: z.string().min(1, 'workflow_name must not be empty'),

  /** Current status of the run. */
  status: WorkflowRunStatusSchema,

  /** Conversation this run belongs to. */
  conversation_id: z.string().min(1, 'conversation_id must not be empty'),

  /** Codebase this run operates on. */
  codebase_id: z.string().min(1, 'codebase_id must not be empty'),

  /** The user message that triggered this run. */
  user_message: z.string().optional(),

  /** Working directory path for the run. */
  working_path: z.string().optional(),

  /** Timestamp when the run was created. */
  created_at: z.string().datetime(),

  /** Timestamp when the run started executing. */
  started_at: z.string().datetime().optional(),

  /** Arbitrary metadata attached to the run. */
  metadata: z.record(z.string(), z.unknown()).default({}),

  /** Parent conversation ID for nested runs. */
  parent_conversation_id: z.string().optional(),
});

export type WorkflowRun = z.infer<typeof WorkflowRunSchema>;