// ── TypeScript Error Parser ──────────────────────────────────────────
// Parses `tsc --noEmit` or `npm run build` output to extract
// "Module not found: Can't resolve '@/path/to/module'" errors.
// Returns actionable missing module info for the generator.
// Used by both setup.mjs (self-heal) and code-repair-agent.mjs.

export interface MissingModule {
  /** The import path that failed, e.g. "@/data/stickers" */
  importPath: string;
  /** The file that contains the failing import */
  importerFile: string;
  /** Line number in importer file */
  line: number;
  /** Column number */
  column: number;
  /** Full error message for context */
  message: string;
  /** Whether this is an internal (@/...) module we can generate */
  isInternal: boolean;
  /** The normalized internal path, e.g. "data/stickers" */
  internalPath?: string;
}

/** Parse TypeScript compiler output for missing module errors (TS2307 + webpack-style "Can't resolve"). */
export function parseMissingModules(tscOutput: string): MissingModule[] {
  const results: MissingModule[] = [];

  // Pattern: error TS2307: Cannot find module '@/data/stickers' or its corresponding type declarations.
  // File: src/components/chats/media-picker.tsx:10:1
  const errorRegex = /error\s+TS\d+:\s+Cannot find module\s+'([^']+)'\s+or its corresponding type declarations\.\s*(?:\n\s*(.*?):(\d+):(\d+))?/g;

  let match;
  while ((match = errorRegex.exec(tscOutput)) !== null) {
    const importPath = match[1];
    const importerFile = match[2] || "";
    const line = parseInt(match[3] || "0", 10);
    const column = parseInt(match[4] || "0", 10);

    // Also handle: Module not found: Error: Can't resolve '@/data/stickers' in 'C:\...\src\components\chats'
    const altRegex = /Module not found: Error: Can't resolve\s+'([^']+)'\s+in\s+'([^']+)'/g;
    let altMatch;
    let altImporter = importerFile;
    while ((altMatch = altRegex.exec(tscOutput)) !== null) {
      if (altMatch[1] === importPath) {
        altImporter = altMatch[2];
        break;
      }
    }

    const isInternal = importPath.startsWith("@/") || importPath.startsWith("~/");

    let internalPath: string | undefined;
    if (isInternal) {
      internalPath = importPath.replace(/^[@~]\//, "");
    }

    results.push({
      importPath,
      importerFile: altImporter,
      line,
      column,
      message: `Cannot find module '${importPath}'`,
      isInternal,
      internalPath,
    });
  }

  // Deduplicate by importPath + importerFile
  const seen = new Set<string>();
  return results.filter((m) => {
    const key = `${m.importPath}|${m.importerFile}`;
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

/** Filter to only internal (@/... or ~/...) modules we can auto-generate from templates. */
export function filterGeneratable(modules: MissingModule[]): MissingModule[] {
  return modules.filter((m) => m.isInternal && m.internalPath);
}

/** Group missing modules by their normalized internal path (deduplicates same module imported from multiple files). */
export function groupByInternalPath(modules: MissingModule[]): Map<string, MissingModule[]> {
  const groups = new Map<string, MissingModule[]>();
  for (const m of modules) {
    if (!m.internalPath) continue;
    const existing = groups.get(m.internalPath) || [];
    existing.push(m);
    groups.set(m.internalPath, existing);
  }
  return groups;
}