import os
import sys
import re
import json
import time
import argparse
from pathlib import Path
from datetime import date
from collections import defaultdict

BASE_DIR = Path(r"C:\fuentes\proyectos delphi\RAUL_ASENCIO\GESTION")
SRC_DIR = BASE_DIR / "src"
AGENTS_DIR = BASE_DIR / ".agents"
WORKFLOWS_DIR = AGENTS_DIR / "workflows"
DOMAINS_DIR = AGENTS_DIR / "domains"
INDEX_FILE = AGENTS_DIR / "INDEX.md"
GRAPH_FILE = AGENTS_DIR / "codebase_graph.json"
SQL_STRUCT_FILE = BASE_DIR / "PASTELERIAS-struct.sql"

DOMAINS_DIR.mkdir(parents=True, exist_ok=True)
WORKFLOWS_DIR.mkdir(parents=True, exist_ok=True)

SQL_TABLE_REGEX = re.compile(r'\b(?:FROM|JOIN|UPDATE|INTO|TABLE)\s+`?(ge_[a-z0-9_]+|ob_[a-z0-9_]+|edi_[a-z0-9_]+)`?', re.IGNORECASE)
ALL_TABLE_REGEX = re.compile(r'\b(ge_[a-z0-9_]+|ob_[a-z0-9_]+|edi_[a-z0-9_]+)\b', re.IGNORECASE)
DFM_OBJECT_REGEX = re.compile(r'object\s+([A-Za-z0-9_]+):\s+([A-Za-z0-9_]+)', re.IGNORECASE)

def parse_ddl_tables():
    if not SQL_STRUCT_FILE.exists():
        return set()
    text = SQL_STRUCT_FILE.read_text(encoding='utf-8', errors='ignore')
    tables = re.findall(r'CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?`?([A-Za-z0-9_]+)`?', text, re.IGNORECASE)
    return set(t.lower() for t in tables)

def run_indexing(auto_create_workflows=False):
    start_time = time.time()
    pas_files = [p for p in SRC_DIR.rglob("*.pas") if "__history" not in str(p) and "__recovery" not in str(p)]
    pas_files.sort(key=lambda p: p.name.lower())

    ddl_tables = parse_ddl_tables()

    file_data = {}
    all_tables = set()
    table_to_modules = defaultdict(set)

    for p in pas_files:
        try:
            text = p.read_text(encoding='utf-8', errors='ignore')
        except Exception:
            text = ''
            
        tokens = set(re.findall(r'\b[A-Za-z0-9_]+\b', text))
        unit_match = re.search(r'unit\s+([A-Za-z0-9_]+);', text, re.IGNORECASE)
        unit_name = unit_match.group(1) if unit_match else p.stem
        
        classes = re.findall(r'\b(T[A-Za-z0-9_]+)\s*=\s*class\b', text)
        form_class = next((c for c in classes if 'frm' in c.lower() or 'form' in c.lower()), classes[0] if classes else '')
        
        uses_list = []
        uses_matches = re.findall(r'uses\s+([^;]+);', text, re.IGNORECASE)
        for um in uses_matches:
            for u in um.split(','):
                u_clean = u.strip()
                if u_clean and u_clean not in uses_list:
                    uses_list.append(u_clean)
                    
        # Extract tables from both SQL constructs and DDL known tokens
        tables_found = set(t.lower() for t in SQL_TABLE_REGEX.findall(text))
        for token_table in ALL_TABLE_REGEX.findall(text):
            t_low = token_table.lower()
            if t_low in ddl_tables:
                tables_found.add(t_low)
        
        dfm_path = p.with_suffix('.dfm')
        dfm_components = []
        if dfm_path.exists():
            try:
                dfm_text = dfm_path.read_text(encoding='utf-8', errors='ignore')
                dfm_components = DFM_OBJECT_REGEX.findall(dfm_text)
                for dt in SQL_TABLE_REGEX.findall(dfm_text):
                    tables_found.add(dt.lower())
                for dt in ALL_TABLE_REGEX.findall(dfm_text):
                    t_low = dt.lower()
                    if t_low in ddl_tables:
                        tables_found.add(t_low)
            except Exception:
                pass
                
        for t in tables_found:
            all_tables.add(t)
            table_to_modules[t].add(p.name)
                
        m_intf = re.search(r'interface\s+(.*?)\s+implementation', text, re.DOTALL | re.IGNORECASE)
        intf_text = m_intf.group(1) if m_intf else ''
        methods = re.findall(r'(?:procedure|function|class\s+procedure|class\s+function)\s+([A-Za-z0-9_]+)', intf_text, re.IGNORECASE)
        methods = [m for m in set(methods) if m.lower() not in ('create', 'destroy', 'free', 'init', 'done')]
        
        wf_name = p.stem.lower() + ".md"
        wf_path = WORKFLOWS_DIR / wf_name
        has_wf = wf_path.exists()
        
        # Auto-generate missing workflow template if requested
        if auto_create_workflows and not has_wf:
            wf_content = [
                f"# Skill: {p.stem.lower()}",
                "",
                "## Metadata",
                f"- **Archivo**: {p.name}",
                f"- **Formulario Delphi**: {form_class or unit_name}",
                f"- **Última Revisión**: {date.today().isoformat()}",
                "",
                "## Overview",
                f"Módulo de {p.parent.name} para gestión en AGRIGEST.",
                "",
                "## Tables Involved (Tablas Implicadas)",
                "",
                "| Tabla | Modo | Uso |",
                "| :--- | :---: | :--- |"
            ]
            for t in sorted(list(tables_found)):
                wf_content.append(f"| `{t}` | R+W | Operaciones del módulo |")
            if not tables_found:
                wf_content.append("| — | — | No utiliza tablas directas |")
            wf_content.append("")
            wf_content.append("## Observaciones y Restricciones")
            wf_content.append("Módulo generado e indexado automáticamente.")
            wf_content.append("")
            wf_path.write_text("\n".join(wf_content), encoding='utf-8')
            has_wf = True

        rel_path = p.relative_to(BASE_DIR).as_posix()
        
        file_data[p.name] = {
            'file': p.name,
            'unit': unit_name,
            'rel_path': rel_path,
            'folder': p.parent.name,
            'form_class': form_class,
            'classes': classes,
            'uses': uses_list,
            'tables': sorted(list(tables_found)),
            'dfm_components_count': len(dfm_components),
            'methods': sorted(methods),
            'tokens': tokens,
            'has_wf': has_wf,
            'wf_name': wf_name,
            'called_by': [],
            'domain_id': None,
            'domain_title': None
        }

    # Calculate dependencies / callers
    for fname, fdata in file_data.items():
        for other_fname, other_fdata in file_data.items():
            if other_fname == fname:
                continue
            if fdata['unit'] in other_fdata['uses'] or (fdata['form_class'] and fdata['form_class'] in other_fdata['tokens']):
                fdata['called_by'].append(other_fname)
        fdata['called_by'].sort()

    orphan_units = [fname for fname, fdata in file_data.items() if not fdata['called_by'] and fname not in ('frm_Main.pas', 'dmg_Main.pas', 'dmg_Calidad.pas', 'Gestion.dpr')]

    # Specific Domain Definitions with Priority Matching
    domain_specs = [
        {
            "id": "02_compras_proveedores",
            "title": "Compras y Proveedores",
            "keywords": ["prov", "factusol", "entradasmateriasprimas"],
            "description": "Gestión integral del ciclo de compras: presupuestos y pedidos a proveedor, cotejo y recepción de albaranes de compra, facturación de acreedores, catálogo de materias primas por proveedor e importación histórica de datos desde Factusol.",
            "mermaid": "graph LR\n    PresupuestoProv[\"Presupuestos Proveedor\"] --> AlbaranProv[\"Albaranes de Entrada\"]\n    AlbaranProv --> Cotejo[\"Cotejo y Asignación Materias Primas\"]\n    AlbaranProv --> FacturaProv[\"Facturas de Proveedor\"]\n    Factusol[\"Importación Factusol\"] --> FacturaProv"
        },
        {
            "id": "05_logistica_envios",
            "title": "Logística, Transporte y Envíos",
            "keywords": ["envio", "tipsa", "nacex", "transportista", "firma", "formatosenvio", "albaranenvioeditor"],
            "description": "Plataforma de expediciones y transporte capilar/frigorífico: integración automatizada con NACEX (REST API) y TIPSA (SOAP WS), generación de etiquetas PDF/ZPL, importador de pedidos web con solicitud de envíos y recogida en tienda con firma digital.",
            "mermaid": "graph LR\n    Albaran[\"Albarán de Venta\"] --> EnvioConfig[\"Configuración Envío / Bultos\"]\n    EnvioConfig --> Nacex[\"NACEX (REST API)\"]\n    EnvioConfig --> Tipsa[\"TIPSA (SOAP WebService)\"]\n    EnvioConfig --> Firma[\"Firma Digital en Tablet\"]"
        },
        {
            "id": "04_calidad_ifs",
            "title": "Calidad, Auditoría e IFS Food v8",
            "keywords": ["calidad", "incidencia", "reporttemplate"],
            "description": "Gestión del sistema de calidad conforme a la norma IFS Food v8: agenda planificadora, verificación diaria de puntos críticos (PCC), documentación de prerrequisitos, registros higiénicos, control de alérgenos, gestión de incidencias y trazabilidad maestra hacia adelante/atrás.",
            "mermaid": "graph LR\n    Prerrequisitos[\"Prerrequisitos / Docs IFS\"] --> Planificador[\"Agenda / Planificador de Tareas\"]\n    Planificador --> Verificacion[\"Verificación Diaria / PCC\"]\n    Verificacion --> Incidencias[\"Registro de Incidencias / AC\"]\n    Verificacion --> Trazabilidad[\"Trazabilidad Maestra IFS\"]"
        },
        {
            "id": "03_produccion_obradores",
            "title": "Producción, Obradores y Trazabilidad",
            "keywords": ["obrador", "receta", "materia", "lote", "inventario", "stock", "fichatecnica", "evento", "alergeno", "formatospresentacion"],
            "description": "Control industrial de obradores de pastelería y panettones: escandallos, recetas maestras y submétodos, refrescos de masa madre, órdenes de elaboración, materias primas, lotes de fabricación, stock envasado, fichas técnicas y gestión de eventos/catering.",
            "mermaid": "graph LR\n    MateriasPrimas[\"Materias Primas + Alérgenos\"] --> Recetas[\"Recetas / Fórmulas / Masa Madre\"]\n    Recetas --> Elaboracion[\"Obradores / Elaboración\"]\n    Elaboracion --> Lotes[\"Lotes de Fabricación\"]\n    Lotes --> StockEnvasado[\"Stock Envasado / Panettones\"]\n    StockEnvasado --> Inventarios[\"Control de Inventarios\"]"
        },
        {
            "id": "01_ventas_facturacion",
            "title": "Ventas, Facturación y VERI*FACTU",
            "keywords": ["factura", "pedido", "albaran", "presupuesto", "verifactu", "sif", "edicom", "webimporter", "printservice"],
            "description": "Ciclo comercial completo de ventas: recepción de pedidos (EDI, Web, PDF IA, manual), preparación y expedición de albaranes, facturación, servicios de impresión / envío de documentos y sellado criptográfico VERI*FACTU / SIF.",
            "mermaid": "graph LR\n    Pedido[\"Pedidos (EDI / Web / PDF / Manual)\"] --> Albaran[\"Albaranes de Entrega\"]\n    Albaran --> Envio[\"Logística / Envíos\"]\n    Albaran --> Factura[\"Facturación Oficial\"]\n    Factura --> VeriFactu[\"VERI*FACTU / SIF (AEAT)\"]\n    Factura --> EDI_Inv[\"EDIFACT Invoice (El Corte Inglés)\"]"
        },
        {
            "id": "06_sistema_ia",
            "title": "Sistema, Seguridad e Inteligencia Artificial",
            "keywords": ["main", "login", "user", "usuario", "company", "empresa", "dbconfig", "dberror", "chatia", "iaservice", "theme", "autoscale", "email", "validacion", "baseform", "baselist", "baseselect", "dbgridhelper"],
            "description": "Núcleo transversal de la aplicación: autenticación y control de accesos, selector multi-empresa, menú principal MDI, formularios base reutilizables, configuración de base de datos MySQL/MariaDB, gestión de errores, servicio de IA multimodal (Google Gemini para análisis SQL y extracción de pedidos en PDF), theming VCL y escalado DPI.",
            "mermaid": "graph LR\n    Login[\"Login y Permisos\"] --> SelectCompany[\"Selección de Empresa\"]\n    SelectCompany --> MainMDI[\"Menú Principal MDI\"]\n    MainMDI --> ChatIA[\"Chat IA (Gemini Multimodal)\"]\n    MainMDI --> PDFOrder[\"Extracción Pedidos PDF IA\"]\n    MainMDI --> ConfigBD[\"Configuración y Auditoría BD\"]"
        },
        {
            "id": "07_maestros_almacenes",
            "title": "Maestros Generales, Clientes y Artículos",
            "keywords": ["cliente", "articulo", "familia", "tipoiva", "almacen", "serie", "codigosbarras", "documentosrelacionados", "formaspago", "enviardocumento", "gs1"],
            "description": "Mantenimiento de entidades maestras transversales: clientes y destinos de entrega con códigos GLN/EAN, tarifas y grupos de precios, artículos y formatos comerciales, jerarquía de familias, almacenes, series de facturación, tipos de IVA y formas de pago.",
            "mermaid": "graph LR\n    Empresa[\"Empresas / Centros\"] --> Series[\"Series de Facturación\"]\n    Empresa --> Clientes[\"Clientes + Destinos EAN / GLN\"]\n    Clientes --> Precios[\"Tarifas y Precios por Grupo\"]\n    Empresa --> Articulos[\"Artículos + EAN-13 + GS1-128\"]\n    Articulos --> Familias[\"Familias de Producto\"]"
        }
    ]

    domain_assignments = {d['id']: [] for d in domain_specs}
    assigned_files = set()

    for d in domain_specs:
        for fname, fdata in file_data.items():
            if fname in assigned_files:
                continue
            fname_lower = fname.lower()
            if any(kw in fname_lower for kw in d['keywords']):
                domain_assignments[d['id']].append(fdata)
                assigned_files.add(fname)
                fdata['domain_id'] = d['id']
                fdata['domain_title'] = d['title']

    for fname, fdata in file_data.items():
        if fname not in assigned_files:
            domain_assignments["07_maestros_almacenes"].append(fdata)
            assigned_files.add(fname)
            fdata['domain_id'] = "07_maestros_almacenes"
            fdata['domain_title'] = "Maestros Generales, Clientes y Artículos"

    # Generate individual domain documents
    for d in domain_specs:
        dom_id = d['id']
        dom_file = DOMAINS_DIR / f"{dom_id}.md"
        assigned = domain_assignments[dom_id]
        dom_tables = set(t for f in assigned for t in f['tables'])
        
        dom_md = []
        dom_md.append(f"# Dominio {dom_id[:2]}: {d['title']}\n")
        dom_md.append(f"## Overview\n{d['description']}\n")
        dom_md.append("## Diagrama de Flujo de Negocio\n```mermaid\n" + d['mermaid'] + "\n```\n")
        dom_md.append(f"## Módulos y Unidades Delphi del Dominio ({len(assigned)} módulos)\n")
        dom_md.append("| Capa | Archivo | Clase / Formulario | Tablas BD | Ficha Workflow |")
        dom_md.append("| :--- | :--- | :--- | :--- | :--- |")
        
        for f in sorted(assigned, key=lambda x: (x['folder'], x['file'])):
            pas_link = f"[{f['file']}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/{f['rel_path']})"
            cls_name = f"`{f['form_class']}`" if f['form_class'] else f"`{f['unit']}`"
            tbl_str = ", ".join(f"`{t}`" for t in f['tables'][:3]) if f['tables'] else "—"
            if len(f['tables']) > 3:
                tbl_str += f" (+{len(f['tables'])-3})"
            wf_link = f"[{f['wf_name']}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/.agents/workflows/{f['wf_name']})" if f['has_wf'] else "—"
            dom_md.append(f"| **{f['folder']}** | {pas_link} | {cls_name} | {tbl_str} | {wf_link} |")
            
        dom_md.append(f"\n## Tablas de Base de Datos Vinculadas ({len(dom_tables)} tablas)\n")
        dom_md.append("| Tabla | Módulos de este Dominio que la Utilizan |")
        dom_md.append("| :--- | :--- |")
        for t in sorted(list(dom_tables)):
            mods = [f['file'] for f in assigned if t in f['tables']]
            dom_md.append(f"| `{t}` | {', '.join(f'`{m}`' for m in mods)} |")
            
        dom_file.write_text("\n".join(dom_md) + "\n", encoding='utf-8')

    today_str = date.today().strftime("%Y-%m-%d")
    
    # Layer counts
    ui_count = sum(1 for f in file_data.values() if f['folder'] == 'UI')
    logic_count = sum(1 for f in file_data.values() if f['folder'] == 'Logic')
    common_count = sum(1 for f in file_data.values() if f['folder'] == 'Common')
    data_count = sum(1 for f in file_data.values() if f['folder'] == 'Data')
    wf_count = sum(1 for f in file_data.values() if f['has_wf'])

    # Build Master INDEX.md
    index_md = [
        "# AGRIGEST / Raúl Asencio — Mapa Maestro del Proyecto (Índice y Arquitectura)\n",
        "> **Propósito**: Punto de entrada de navegación técnica y funcional para Agentes de IA y Desarrolladores.",
        "> Consulta los dominios específicos en `.agents/domains/` o las fichas técnicas individuales en `.agents/workflows/`.",
        f"> **Última Actualización**: {today_str} | **Módulos**: {len(file_data)} | **Formularios VCL**: {ui_count} | **Tablas BD**: {len(all_tables)} (en código) / {len(ddl_tables)} (en DDL) | **Workflows**: {wf_count}/{len(file_data)} (100%)\n",
        "---\n",
        "## 🗺️ Mapa de Dominios de Negocio\n",
        "| Dominio | Título del Dominio | Módulos | Tablas BD | Propósito y Ámbito Funcional | Enlace Directo |",
        "| :---: | :--- | :---: | :---: | :--- | :--- |"
    ]
    for d in sorted(domain_specs, key=lambda x: x['id']):
        assigned = domain_assignments[d['id']]
        d_tables = set(t for f in assigned for t in f['tables'])
        link = f"[{d['id']}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/.agents/domains/{d['id']}.md)"
        index_md.append(f"| **{d['id'][:2]}** | **{d['title']}** | {len(assigned)} | {len(d_tables)} | {d['description'][:80]}... | {link} |")
    
    index_md.append("\n---\n")
    index_md.append("## 🏛️ Arquitectura de Capas de la Aplicación\n")
    index_md.append("```")
    index_md.append(f"┌─────────────────────────────────────────────────────────────────────────────────┐")
    index_md.append(f"│  src/UI ({ui_count:3d} unidades)     — Formularios VCL (Heredados de BaseList y Base)          │")
    index_md.append(f"├─────────────────────────────────────────────────────────────────────────────────┤")
    index_md.append(f"│  src/Logic ({logic_count:2d} unidades)   — Servicios de Negocio (IA, Envíos, SIF, Lotes, Impresión)│")
    index_md.append(f"├─────────────────────────────────────────────────────────────────────────────────┤")
    index_md.append(f"│  src/Common ({common_count:2d} unidades)  — Utilidades, Temas VCL, Tipos SIF, Validaciones, GS1     │")
    index_md.append(f"├─────────────────────────────────────────────────────────────────────────────────┤")
    index_md.append(f"│  src/Data ({data_count:2d} DataModules) — dmg_Main (Conexión BD central), dmg_Calidad (IFS)       │")
    index_md.append(f"└─────────────────────────────────────────────────────────────────────────────────┘")
    index_md.append("```\n")

    index_md.append("## 📋 Reglas Arquitectónicas y Convenciones Críticas\n")
    index_md.append("1. **Seguridad y Base de Datos**: FireDAC con parámetros obligatorios (`:param`). Prohibido ejecutar DDL/DML de forma autónoma. Nombres exactos siempre contrastados contra [`PASTELERIAS-struct.sql`](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/PASTELERIAS-struct.sql).")
    index_md.append("2. **UTF-8 y Unicode en MariaDB**: Asignar parámetros de texto en FireDAC con `DataType := ftWideString` y `AsWideString`. En `UNION ALL`, aplicar siempre `CONVERT(campo USING utf8mb4) COLLATE utf8mb4_general_ci`.")
    index_md.append("3. **Estilo Delphi 11**: Prefijos estándar `L` para variables locales y `A` para parámetros. Prohibidas variables en línea (`var x := ...`). Métodos `OnGetText` en `TField` deben ser miembros de clase.")
    index_md.append("4. **Directiva DBGrid**: Renderizado automático de checkboxes en columnas booleanas o de estado activo (`activo`/`active`). Ordenación dinámica al hacer clic en cabeceras (`OnTitleClick`).")
    index_md.append("5. **Exclusión de Change Tracking (`Tag = 999`)**: Todo control que no edite el registro principal (filtros de rejilla, cuadros de búsqueda, combos auxiliares) DEBE marcarse con `Tag = 999`.")
    index_md.append("6. **Ayuda Contextual Obligatoria**: Todo formulario de usuario (`UI/`) dispone de su archivo de ayuda en texto plano en `help/T[NombreFormulario].txt`.")
    index_md.append("7. **Grafo de Código Completo**: Estructura de dependencias, llamadas y métodos disponible en [`.agents/codebase_graph.json`](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/.agents/codebase_graph.json).\n")

    index_md.append("---\n")
    index_md.append("## 📦 Índice Maestro de Módulos (Directorio Alfabético Completo)\n")
    index_md.append("| Módulo (.pas) | Capa | Clase / Formulario | Dominio | Tablas BD | Invocado por (`called_by`) | Ficha Workflow |")
    index_md.append("| :--- | :---: | :--- | :--- | :--- | :--- | :---: |")

    for fname in sorted(file_data.keys(), key=lambda s: s.lower()):
        f = file_data[fname]
        pas_link = f"[{f['file']}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/{f['rel_path']})"
        cls_name = f"`{f['form_class']}`" if f['form_class'] else f"`{f['unit']}`"
        dom_link = f"[{f['domain_id'][:2]}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/.agents/domains/{f['domain_id']}.md)"
        tbl_str = ", ".join(f"`{t}`" for t in f['tables'][:2]) if f['tables'] else "—"
        if len(f['tables']) > 2:
            tbl_str += f" (+{len(f['tables'])-2})"
        called_str = f"{len(f['called_by'])} módulos" if f['called_by'] else "*Punto de entrada / Raíz*"
        wf_link = f"[{f['wf_name']}](file:///c:/fuentes/proyectos%20delphi/RAUL_ASENCIO/GESTION/.agents/workflows/{f['wf_name']})" if f['has_wf'] else "—"
        index_md.append(f"| {pas_link} | **{f['folder']}** | {cls_name} | {dom_link} | {tbl_str} | {called_str} | {wf_link} |")

    index_md.append("\n---\n")
    index_md.append("## 🗄️ Matriz de Tablas de Base de Datos y Módulos Implicados\n")
    index_md.append("| Tabla BD | Módulos Delphi que la Utilizan | Total Módulos |")
    index_md.append("| :--- | :--- | :---: |")
    for t in sorted(all_tables):
        mods = sorted(list(table_to_modules[t]))
        mods_preview = ", ".join(f"`{m}`" for m in mods[:4])
        if len(mods) > 4:
            mods_preview += f" *(+{len(mods)-4} más)*"
        index_md.append(f"| `{t}` | {mods_preview} | {len(mods)} |")

    INDEX_FILE.write_text("\n".join(index_md) + "\n", encoding='utf-8')

    graph_export = {
        'version': '6.0',
        'generated_at': date.today().isoformat(),
        'stats': {
            'total_units': len(file_data),
            'ui_forms_count': ui_count,
            'logic_units_count': logic_count,
            'common_units_count': common_count,
            'datamodules_count': data_count,
            'total_tables_detected': len(all_tables),
            'ddl_tables_count': len(ddl_tables),
            'workflows_count': wf_count,
            'orphan_units_count': len(orphan_units)
        },
        'orphan_units': orphan_units,
        'tables_map': {t: sorted(list(mods)) for t, mods in sorted(table_to_modules.items())},
        'modules': {
            k: {
                'layer': v['folder'],
                'unit': v['unit'],
                'class': v['form_class'],
                'domain': v['domain_id'],
                'tables': v['tables'],
                'dfm_components': v['dfm_components_count'],
                'uses': [u for u in v['uses'] if u in [f['unit'] for f in file_data.values()]],
                'called_by': v['called_by'],
                'methods_count': len(v['methods']),
                'has_workflow': v['has_wf'],
                'workflow_file': v['wf_name'] if v['has_wf'] else None
            }
            for k, v in file_data.items()
        }
    }
    GRAPH_FILE.write_text(json.dumps(graph_export, indent=2, ensure_ascii=False), encoding='utf-8')
    print(f"[Iteración 6] Reindexación y Actualización del Mapa completada en {time.time()-start_time:.2f}s!")
    return file_data, all_tables, ddl_tables

def cli_query(keyword):
    if not GRAPH_FILE.exists():
        run_indexing()
    data = json.loads(GRAPH_FILE.read_text(encoding='utf-8'))
    kw = keyword.lower()
    
    print(f"\n🔍 RESULTADOS DE BÚSQUEDA PARA '{keyword}':")
    print("=" * 60)
    
    matching_tables = {t: mods for t, mods in data.get('tables_map', {}).items() if kw in t.lower()}
    if matching_tables:
        print(f"\n📊 TABLAS DE BASE DE DATOS ({len(matching_tables)} encontradas):")
        for t, mods in matching_tables.items():
            print(f"  • {t} -> Usada en {len(mods)} módulos: {', '.join(mods[:5])}{' (+'+str(len(mods)-5)+')' if len(mods)>5 else ''}")
            
    matching_modules = {k: v for k, v in data['modules'].items() if kw in k.lower() or kw in (v.get('class') or '').lower()}
    if matching_modules:
        print(f"\n📦 MÓDULOS DELPHI ({len(matching_modules)} encontrados):")
        for k, v in matching_modules.items():
            print(f"  • {k} [{v['layer']}] ({v['class'] or v['unit']}) - Dominio: {v.get('domain', 'N/A')}")
            print(f"    - Tablas: {', '.join(v['tables']) if v['tables'] else 'Ninguna'}")
            print(f"    - Invocado por ({len(v['called_by'])}): {', '.join(v['called_by'][:4])}{' (+'+str(len(v['called_by'])-4)+')' if len(v['called_by'])>4 else ''}")
            print(f"    - Workflow: {'✅ ' + v['workflow_file'] if v['has_workflow'] else '❌ Falta workflow'}")

def cli_check_integrity():
    if not GRAPH_FILE.exists():
        run_indexing()
    data = json.loads(GRAPH_FILE.read_text(encoding='utf-8'))
    ddl_tables = parse_ddl_tables()
    code_tables = set(data.get('tables_map', {}).keys())
    
    print("\n🛡️ AUDITORÍA DE INTEGRIDAD DEL PROYECTO (Delphi + MySQL DDL):")
    print("=" * 60)
    print(f"• Total Unidades Delphi: {data['stats']['total_units']}")
    print(f"  - UI (Formularios VCL): {data['stats']['ui_forms_count']}")
    print(f"  - Logic (Servicios de Negocio): {data['stats']['logic_units_count']}")
    print(f"  - Common (Helpers transversales): {data['stats']['common_units_count']}")
    print(f"  - Data (DataModules): {data['stats']['datamodules_count']}")
    print(f"• Cobertura de Workflows: {data['stats']['workflows_count']} / {data['stats']['total_units']} ({data['stats']['workflows_count']/data['stats']['total_units']*100:.1f}%)")
    print(f"• Tablas en DDL (PASTELERIAS-struct.sql): {len(ddl_tables)}")
    print(f"• Tablas referenciadas en código: {len(code_tables)}")
    
    unmatched_in_ddl = [t for t in code_tables if t not in ddl_tables and not t.startswith('ge_sif') and not t.startswith('ge_facturas_rect')]
    if unmatched_in_ddl:
        print(f"⚠️ Tablas en código que no están en el DDL base: {', '.join(unmatched_in_ddl[:6])}")
        
    print(f"• Módulos Huérfanos / No referenciados: {len(data['orphan_units'])}")
    if data['orphan_units']:
        print("  - " + ", ".join(data['orphan_units'][:8]) + ("..." if len(data['orphan_units'])>8 else ""))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="AGRIGEST Delphi Codebase Indexer & Query Tool")
    parser.add_argument('--query', '-q', type=str, help="Buscar tabla, módulo o clase")
    parser.add_argument('--check-integrity', '-c', action='store_true', help="Auditoría de integridad")
    parser.add_argument('--auto-workflows', '-w', action='store_true', help="Crear workflows faltantes")
    
    args = parser.parse_args()
    if args.query:
        cli_query(args.query)
    elif args.check_integrity:
        cli_check_integrity()
    elif args.auto_workflows:
        run_indexing(auto_create_workflows=True)
    else:
        run_indexing()
