/**
 * cli:scaffold-tests-from-ac — types.ts
 *
 * Generates ONE xUnit `[Fact]` per Acceptance Criterion (AC) declared under each
 * use case in `.smartstack/ba/<APP>/<MODULE>/<section>/use-case.md`. The body is
 * a structured TODO that the `/ba-develop` Phase 5 subagent fills in by reading
 * the AC text + the entity DTO + the controller. The audit `DEV-TEST-001`
 * (Wave 3) verifies no TODO remains on merge.
 *
 * Read the use-case.md format in
 * `templates/skills/business-analyse/_workflow/doc-templates.md` (AC subsection).
 *
 * Zero MCP. Zero LLM at scaffold time — pure structural emission.
 */

import { z } from 'zod'

/** A single `- [ ] AC-NN — <text>` bullet under a UC's `**Acceptance Criteria**` field. */
export const AcSchema = z.object({
  /** `AC-01`, `AC-02`, … — local to the parent UC, zero-padded 2 digits. */
  localId: z.string().regex(/^AC-\d{2}$/, 'Expected AC-NN (2 digits)'),
  /** Verbatim text after the ` — ` separator. */
  text: z.string().min(1),
})

export type Ac = z.infer<typeof AcSchema>

/** A `### UC-{APP}-{MOD}-{SEC}-NNN — Title` heading + its parsed ACs. */
export const UcWithAcSchema = z.object({
  /** Verbatim UC code from the heading (e.g. `UC-CRM-PIPELINE-OPPORTUNITES-001`). */
  ucCode: z.string().regex(/^UC-[A-Z0-9_]+-[A-Z0-9_]+-[A-Z0-9_]+-\d{3}$/, 'Expected UC-{APP}-{MOD}-{SEC}-NNN'),
  /** UC title (text after the ` — ` in the heading). */
  title: z.string().min(1),
  /** Section folder code in UPPERCASE (e.g. `OPPORTUNITES`) — derived from ucCode. */
  sectionCode: z.string().min(1),
  /** Section folder code in kebab-case (e.g. `opportunites`) — derived from path. */
  sectionFolder: z.string().min(1),
  /** Source file (relative to moduleDir) for traceability in errors. */
  sourceFile: z.string().min(1),
  /** ACs found under this UC (may be empty — Audit UC-012 warns on `user-goal` UCs). */
  acs: z.array(AcSchema).default([]),
})

export type UcWithAc = z.infer<typeof UcWithAcSchema>

export const ScaffoldTestsFromAcSpecSchema = z.object({
  /**
   * Absolute path to the BA module folder
   * (e.g. `D:/project/.smartstack/ba/CRM/PIPELINE`). Glob is run against
   * `<moduleDir>/<section>/use-case.md`.
   */
  moduleDir: z.string().min(1),

  /**
   * Absolute path to the generated-app root (where `*.Tests.csproj` lives).
   * The CLI writes tests to `{projectPath}/Tests/{Module}/Acceptance/...`.
   */
  projectPath: z.string().min(1),

  /** Lowercase application code (e.g. `crm`) — used to build the namespace prefix. */
  appCode: z.string().min(1).regex(/^[a-z][a-z0-9-]*$/, 'Expected lowercase kebab appCode'),

  /** Lowercase module code (e.g. `pipeline`). */
  module: z.string().min(1).regex(/^[a-z][a-z0-9-]*$/, 'Expected lowercase kebab module'),

  /**
   * Optional namespace prefix override. When absent, the CLI uses
   * `{Pascal(appCode)}.Tests.{Pascal(module)}.Acceptance`.
   */
  namespace: z.string().optional(),

  /**
   * When true, the CLI parses + plans + returns the would-be file paths but
   * writes nothing. Used by the dev orchestrator for pre-flight coverage checks.
   */
  dryRun: z.boolean().optional().default(false),
})

export type ScaffoldTestsFromAcSpec = z.infer<typeof ScaffoldTestsFromAcSpecSchema>

/** One emitted .cs file. */
export const GeneratedFileSchema = z.object({
  path: z.string().min(1),
  content: z.string(),
})

export type GeneratedFile = z.infer<typeof GeneratedFileSchema>

export const ScaffoldTestsFromAcResultSchema = z.object({
  success: z.boolean(),
  error: z.string().optional(),
  /** Total UC headings scanned (across every section). */
  ucsScanned: z.number(),
  /** Total AC bullets parsed (across every UC). */
  acsParsed: z.number(),
  /** Total `[Fact]` methods emitted. */
  factsEmitted: z.number(),
  /** Test files emitted (one per section that has ≥1 UC with ≥1 AC). */
  filesCreated: z.array(z.string()),
  /** Non-fatal issues (e.g. UC without AC field, malformed bullets). */
  warnings: z.array(z.string()),
})

export type ScaffoldTestsFromAcResult = z.infer<typeof ScaffoldTestsFromAcResultSchema>
