import { transpilePhase2Guard } from "@specverse/engines/inference";
function generatePrismaGuards(context) {
  const { model } = context;
  if (!model) {
    throw new Error("Model is required for guards generation");
  }
  const constraints = model.constraints ?? [];
  if (constraints.length === 0) {
    return generateEmptyGuardsModule(model.name);
  }
  const guardFns = [];
  const constraintsTable = [];
  for (const c of constraints) {
    const transpiled = transpilePhase2Guard(
      c.requires.name,
      c.requires.params ?? `self: any, actor: any`,
      c.requires.body
    );
    guardFns.push(transpiled.typescript);
    const onArrayLiteral = `[${c.on.map((o) => JSON.stringify(o)).join(", ")}]`;
    const sourceLiteral = JSON.stringify(
      c.requires.source.input ?? ""
    );
    constraintsTable.push(
      `  {
    on: ${onArrayLiteral},
    guard: ${c.requires.name},
    name: ${JSON.stringify(c.requires.name)},
    source: ${sourceLiteral}
  }`
    );
  }
  return `/**
 * Auto-generated by SpecVerse Phase 2 (Validate-Centric Constraints).
 *
 * Guard functions for ${model.name}'s declared constraints.
 * DO NOT EDIT \u2014 regenerated on every \`spv realize all\`.
 *
 * Slice 1 limitations:
 *   - \`self\` is the input payload (not the loaded entity). For Update/Delete/
 *     Evolve, paths through \`self\` see only the fields the caller sent.
 *   - \`actor\` defaults to null. Constraints using \`actor.*\` paths fail at
 *     runtime when called without a user context.
 */

export interface Violation {
  constraint: string;
  scope: string;
  source: string;
  message: string;
}

export interface ConstraintRecord {
  on: string[];
  guard: (self: any, actor: any) => boolean;
  name: string;
  source: string;
}

${guardFns.join("\n\n")}

export const MODEL_CONSTRAINTS: ConstraintRecord[] = [
${constraintsTable.join(",\n")}
];

/**
 * Match a runtime operation against a constraint's \`on:\` array.
 *
 * Op shapes:
 *   - exact string: 'create', 'update', 'delete', 'retrieve'
 *   - 'evolve.<transition>': specific lifecycle transition
 *
 * \`on:\` entry shapes:
 *   - '*': always matches
 *   - 'evolve.*': matches any 'evolve.X' op
 *   - else: exact-string equality
 */
export function matchesOp(constraintOn: string[], op: string): boolean {
  for (const o of constraintOn) {
    if (o === '*') return true;
    if (o === op) return true;
    if (o === 'evolve.*' && op.startsWith('evolve.')) return true;
  }
  return false;
}

/**
 * Run all constraints whose \`on:\` matches the requested op. Each guard
 * is invoked with (input, actor). Returns the collected violations.
 *
 * A guard that returns false produces one Violation; a guard that throws
 * (e.g. actor=null with an actor.* path) is caught and surfaced as a
 * violation with the thrown message \u2014 fail closed.
 */
export function runGuards(
  input: any,
  op: string,
  actor: any = null,
): Violation[] {
  const violations: Violation[] = [];
  for (const c of MODEL_CONSTRAINTS) {
    if (!matchesOp(c.on, op)) continue;
    let passed = false;
    let thrown: string | null = null;
    try {
      passed = c.guard(input, actor);
    } catch (e: any) {
      thrown = e?.message ?? String(e);
    }
    if (!passed) {
      violations.push({
        constraint: c.name,
        scope: op,
        source: c.source,
        message: thrown
          ? \`Constraint "\${c.source}" could not be evaluated: \${thrown}\`
          : \`Constraint "\${c.source}" failed\`,
      });
    }
  }
  return violations;
}
`;
}
function generateEmptyGuardsModule(modelName) {
  return `/**
 * Auto-generated by SpecVerse Phase 2 \u2014 no constraints declared on ${modelName}.
 * Empty stub kept for symmetry; controllers gate their imports on this file.
 */

export interface Violation {
  constraint: string;
  scope: string;
  source: string;
  message: string;
}

export const MODEL_CONSTRAINTS: any[] = [];

export function matchesOp(_constraintOn: string[], _op: string): boolean {
  return false;
}

export function runGuards(_input: any, _op: string, _actor: any = null): Violation[] {
  return [];
}
`;
}
export {
  generatePrismaGuards as default
};
