import { z } from 'zod';

/**
 * Configuration for a loop-type DAG node.
 *
 * The loop repeatedly invokes the model with the given prompt until the
 * `until` condition is satisfied or `max_iterations` is reached.
 * When `interactive` is true, a human gate must approve each iteration.
 */
export const loopNodeConfigSchema = z
  .object({
    /** The prompt sent to the model on each iteration. */
    prompt: z.string().min(1, 'loop prompt must not be empty'),

    /** Natural-language condition that must be true for the loop to exit. */
    until: z.string().min(1, 'loop until condition must not be empty'),

    /** Maximum iterations before the loop is force-stopped. */
    max_iterations: z
      .number()
      .int()
      .positive('max_iterations must be a positive integer'),

    /** Whether each iteration starts with a fresh context window. */
    fresh_context: z.boolean().default(false),

    /** Optional bash command whose exit code is used as the until-check. */
    until_bash: z.string().optional(),

    /** When true, a human must approve each iteration before it proceeds. */
    interactive: z.boolean().optional(),

    /** Message shown to the human gate when interactive is true. */
    gate_message: z.string().optional(),
  })
  .superRefine((config, ctx) => {
    if (config.interactive && !config.gate_message) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'gate_message is required when interactive is true',
        path: ['gate_message'],
      });
    }
  });

export type LoopNodeConfig = z.infer<typeof loopNodeConfigSchema>;