import { promises as fs } from 'fs';
import * as path from 'path';
import { createHash } from 'crypto';

export type Audiencia = 'usuario' | 'dev';

export interface DocSource {
  origen_path: string; // relativa al root pasado
  titulo: string;
  contenido_md: string;        // contenido SIN frontmatter (listo para chunkear/embeddear)
  screen_key: string | null;
  version_hash: string;        // hash del contenido raw original (con frontmatter) — detecta cualquier cambio
  audiencia: Audiencia;        // 'usuario' va a la BD IA; 'dev' se descarta
  aliases: string[];           // términos extra para boost de recall (paso futuro)
}

interface Frontmatter {
  screen_key?: string | null;
  audiencia?: Audiencia;
  titulo?: string;
  aliases?: string[];
}

/**
 * Lee recursivamente los .md a partir del directorio dado (entra a subcarpetas).
 *
 * Reglas de clasificación (audiencia):
 *   1. Si el .md declara `audiencia:` en frontmatter YAML → eso manda.
 *   2. Si no, por ubicación: solo lo que vive en `guias/` es 'usuario'; todo el
 *      resto es 'dev'.
 * Solo los 'usuario' se ingieren a la BD IA.
 *
 * El default es 'dev' a propósito: `docs/` es mayormente documentación interna
 * (planes, QA, arquitectura, PRDs). Cuando el default era 'usuario' salvo unos
 * pocos prefijos, ese material entraba al índice del asistente y el modelo
 * terminaba citando índices de documentación técnica como si fueran pantallas,
 * inventando rutas de menú. Un doc funcional que viva fuera de `guias/` tiene
 * que declarar `audiencia: usuario` en su frontmatter para entrar.
 *
 * `origen_path` se devuelve como ruta relativa al `rootPath` (con separadores `/`),
 * por ej. `guias/guia-empresa.md`. Sirve como clave estable para detectar huérfanos.
 */
export async function extraerMarkdowns(rootPath: string): Promise<DocSource[]> {
  const docs: DocSource[] = [];
  await recorrer(rootPath, rootPath, docs);
  return docs;
}

async function recorrer(rootPath: string, dirActual: string, docs: DocSource[]): Promise<void> {
  let entries: import('fs').Dirent[];
  try {
    entries = await fs.readdir(dirActual, { withFileTypes: true });
  } catch {
    return;
  }
  for (const e of entries) {
    const abs = path.join(dirActual, e.name);
    if (e.isDirectory()) {
      if (e.name.startsWith('.') || e.name === 'node_modules') continue;
      await recorrer(rootPath, abs, docs);
      continue;
    }
    if (!e.isFile() || !e.name.endsWith('.md')) continue;
    const contenidoRaw = await fs.readFile(abs, 'utf8');
    if (contenidoRaw.trim().length === 0) continue;
    const rel = path.relative(rootPath, abs).split(path.sep).join('/');
    const fileBase = path.basename(e.name, '.md');
    const { frontmatter, body } = separarFrontmatter(contenidoRaw);
    const audiencia: Audiencia = frontmatter.audiencia ?? inferirAudiencia(rel);
    const titulo = frontmatter.titulo ?? extraerTitulo(body) ?? fileBase;
    const screen_key =
      frontmatter.screen_key !== undefined
        ? frontmatter.screen_key || null
        : inferirScreenKey(fileBase);
    docs.push({
      origen_path: rel,
      titulo,
      contenido_md: body,
      screen_key,
      version_hash: hashContenido(contenidoRaw),
      audiencia,
      aliases: frontmatter.aliases ?? [],
    });
  }
}

function extraerTitulo(md: string): string | null {
  const m = md.match(/^#\s+(.+)$/m);
  return m ? m[1].trim() : null;
}

/**
 * Sin frontmatter explícito, solo `guias/` cuenta como documentación de usuario.
 * Todo lo demás en `docs/` (planes, QA, docs-auxiliar, docs-pdf, notas sueltas)
 * es material interno y no debe llegar al asistente.
 */
function inferirAudiencia(relPath: string): Audiencia {
  return relPath.toLowerCase().startsWith('guias/') ? 'usuario' : 'dev';
}

function inferirScreenKey(fileBase: string): string | null {
  // Legacy: "plan-rrhh.md" → "rrhh", "guia-apertura-cierre-caja.md" → "apertura/cierre/caja"
  // (no escala — usar frontmatter `screen_key:` en docs nuevos)
  let key = fileBase
    .replace(/^plan-/, '')
    .replace(/^doc-/, '')
    .replace(/^guia-/, '')
    .toLowerCase();
  if (!key) return null;
  return key.replace(/-/g, '/');
}

function hashContenido(s: string): string {
  return createHash('sha256').update(s).digest('hex');
}

/**
 * Parser minimalista de frontmatter YAML. Soporta:
 *   - key: valor
 *   - key: [a, b, c]            (inline list)
 *   - key:                       (multi-line list — items en líneas siguientes "  - x")
 *     - a
 *     - b
 *   - key: null                  (mapea a `null`)
 * Suficiente para nuestras 4 keys. Si crece, migrar a `js-yaml`.
 */
function separarFrontmatter(raw: string): { frontmatter: Frontmatter; body: string } {
  const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
  if (!m) return { frontmatter: {}, body: raw };
  const yamlText = m[1];
  const body = raw.slice(m[0].length);
  const fm: Frontmatter = {};
  const lines = yamlText.split(/\r?\n/);
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const kv = line.match(/^([a-zA-Z_][\w-]*)\s*:\s*(.*)$/);
    if (!kv) continue;
    const key = kv[1].trim();
    const valRaw = kv[2].trim();

    if (key === 'aliases') {
      if (valRaw === '') {
        // Multi-line list: consumir líneas siguientes que empiezan con "  - ..."
        const items: string[] = [];
        while (i + 1 < lines.length) {
          const next = lines[i + 1];
          const item = next.match(/^\s+-\s+(.*)$/);
          if (!item) break;
          const v = item[1].trim().replace(/^["']|["']$/g, '');
          if (v) items.push(v);
          i++;
        }
        fm.aliases = items;
      } else {
        const arr = valRaw.match(/^\[(.*)\]$/);
        if (arr) {
          fm.aliases = arr[1]
            .split(',')
            .map((s) => s.trim().replace(/^["']|["']$/g, ''))
            .filter(Boolean);
        }
      }
      continue;
    }

    if (valRaw === '' || valRaw.toLowerCase() === 'null') {
      if (key === 'screen_key') fm.screen_key = null;
      continue;
    }
    const val = valRaw.replace(/^["']|["']$/g, '');
    if (key === 'audiencia') {
      if (val === 'usuario' || val === 'dev') fm.audiencia = val;
    } else if (key === 'screen_key') {
      fm.screen_key = val;
    } else if (key === 'titulo') {
      fm.titulo = val;
    }
  }
  return { frontmatter: fm, body };
}
