/**
 * types.ts — Zod input schema + internal types for reconcile-menu CLI.
 *
 * Scans the .smartstack/ba/ tree, parses UC/SCR/BR codes embedded in downstream
 * docs (use-case.md, screen.md, règles-métier.md, rbac.md), and detects:
 *   - RENAME: a section/module was renamed in the menu but its codes still
 *             reference the old name in downstream docs.
 *   - DELETE: a section/module was removed and its codes are stranded.
 *   - STALE REFS: cross-doc references (linkedUseCases, écrans liés) to
 *                 codes that no longer exist.
 */
import { z } from 'zod';

// ---------------------------------------------------------------------------
// Input schema (Zod)
// ---------------------------------------------------------------------------

export const ReconcileInputSchema = z
  .object({
    /** Absolute or cwd-relative path to the .smartstack/ba/ directory. */
    baRoot: z.string().min(1),
    /** Optional scope to specific applications (UPPERCASE codes). */
    apps: z
      .array(z.string().regex(/^[A-Z][A-Z0-9_-]*$/))
      .optional(),
    /** If true, no file is written — the envelope reports the plan only. */
    dryRun: z.boolean().optional().default(false),
  })
  .strict();

export type ReconcileInput = z.infer<typeof ReconcileInputSchema>;

// ---------------------------------------------------------------------------
// Section triplet — canonical "APP/MOD/SEC"
// ---------------------------------------------------------------------------

export type SectionKey = `${string}/${string}/${string}`;
export type ModuleKey = `${string}/${string}`;

export function sectionKey(app: string, mod: string, sec: string): SectionKey {
  return `${app}/${mod}/${sec}` as SectionKey;
}

export function modKey(app: string, mod: string): ModuleKey {
  return `${app}/${mod}` as ModuleKey;
}

// ---------------------------------------------------------------------------
// Parsed code (UC / SCR / BR / RBAC)
// ---------------------------------------------------------------------------

export type CodeKind = 'UC' | 'SCR' | 'BR' | 'RBAC';

export interface ParsedCode {
  kind: CodeKind;
  app: string;
  mod: string;
  sec: string;
  num: string;
  /** Full code, verbatim (e.g. "UC-CRM-PIPELINE-OPPORTUNITES-001"). */
  full: string;
  /** Absolute path of the file the code was extracted from. */
  file: string;
  /** Title (first line text after the code) when extractable. */
  title?: string;
}

// ---------------------------------------------------------------------------
// Scan result
// ---------------------------------------------------------------------------

export interface ScanResult {
  /** Sections that currently exist in the menu tree. */
  existingSections: Set<SectionKey>;
  /** Modules that currently exist (derived from sections + module index.md). */
  existingModules: Set<ModuleKey>;
  /** All codes extracted from downstream docs, grouped by file. */
  codesByFile: Map<string, ParsedCode[]>;
  /** All sections that codes point to (may include orphans). */
  referencedSections: Set<SectionKey>;
}

// ---------------------------------------------------------------------------
// Detection output (rename / delete / stale-ref)
// ---------------------------------------------------------------------------

export type ChangeKind = 'section' | 'module';

export interface RenameChange {
  kind: ChangeKind;
  /** Old key (referenced by codes but absent from tree). */
  from: SectionKey | ModuleKey;
  /** New key (present in tree, no codes yet, matched by heuristic). */
  to: SectionKey | ModuleKey;
  /** Confidence score 0..1 (sum of code similarity + UC overlap). */
  confidence: number;
  /** Human-readable reason: "code-similar", "uc-overlap", or both. */
  reason: string;
}

export interface DeletionChange {
  kind: ChangeKind;
  /** Key that is referenced but no longer in the tree, no rename match. */
  path: SectionKey | ModuleKey;
  /** Count of codes that will be removed. */
  codeCount: number;
  /** Why no rename match (no candidate, ambiguous, etc.). */
  reason: string;
}

export interface StaleRef {
  /** File that contains the stale reference. */
  file: string;
  /** The reference string, e.g. "UC-CRM-PIPELINE-LEGACY-001". */
  ref: string;
  /** Whether the ref is a heading (`### UC-…`) or a body cite (in Règles liées). */
  source: 'heading' | 'body';
  kind: CodeKind;
}

export interface ReconcilePlan {
  renames: RenameChange[];
  deletions: DeletionChange[];
  staleRefs: StaleRef[];
}

// ---------------------------------------------------------------------------
// Validation
// ---------------------------------------------------------------------------

export interface ValidationResult {
  valid: boolean;
  spec?: ReconcileInput;
  errors: string[];
  warnings: string[];
}
