// ROCA GOLF — Reporte IA: análisis de presupuesto por proyecto (Claude)
// El servidor calcula todos los montos (SQL real); la IA solo narra sobre ellos:
// claves de riesgo, oportunidades de eficiencia, una propuesta global de presupuesto
// (estimación, no dato oficial) y una calificación de qué tan bien se presupuestó.
// Cada clic en "Generar" produce un análisis fresco y lo guarda en el historial.

const RIA_SEV_CLASS = { alto: 'over', medio: 'alert', bajo: 'warn' };
const RIA_SEV_LABEL = { alto: 'Riesgo alto', medio: 'Riesgo medio', bajo: 'Riesgo bajo' };

function RiaSevTag({ sev }) {
  const cls = RIA_SEV_CLASS[sev] || 'alert';
  return <span className={"rg-alert-tag " + cls}>{RIA_SEV_LABEL[sev] || 'Riesgo'}</span>;
}

// Lee los colores de severidad de las CSS vars (mismo patrón que rgTheme, que no
// expone warn/alert porque esas gráficas no las necesitaban hasta ahora).
function riaFlagColors() {
  const cs = getComputedStyle(document.documentElement);
  const v = (name, fb) => { const x = (cs.getPropertyValue(name) || '').trim(); return x || fb; };
  return {
    ok:    v('--rg-flag-ok',    '#2d6a44'),
    warn:  v('--rg-flag-warn',  '#d4a017'),
    alert: v('--rg-flag-alert', '#c8651b'),
    over:  v('--rg-flag-over',  '#b22222'),
  };
}

function riaMoney(n) { try { return '$' + fmtMoney(Number(n) || 0); } catch { return '$' + (Number(n) || 0).toFixed(2); } }

function RiaKpi({ label, value, valueColor, sub }) {
  return (
    <div className="rg-kpi" style={{ padding: '14px 16px' }}>
      <div className="label" style={{ fontSize: 10.5 }}>{label}</div>
      <div className="value" style={{ fontSize: 22, marginTop: 6, color: valueColor || 'var(--rg-ink)', fontWeight: 700 }}>{value}</div>
      {sub && <div style={{ fontSize: 11, color: 'var(--rg-muted)', marginTop: 4, fontFamily: 'var(--rg-font-mono)' }}>{sub}</div>}
    </div>
  );
}

function riaScoreColor(score) {
  return score >= 85 ? 'var(--rg-flag-ok)' : (score >= 60 ? 'var(--rg-flag-warn)' : 'var(--rg-flag-over)');
}

// ── Gráficas ─────────────────────────────────────────────────────────────────
function RiaGruposChart({ grupos, theme }) {
  if (!grupos || !grupos.length) {
    return <div style={{ padding: 28, textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5 }}>Sin Proyección de Costos configurada para este proyecto todavía.</div>;
  }
  return (
    <RgChart type="bar" height={260}
      data={{
        labels: grupos.map(g => g.nombre),
        datasets: [
          { label: 'Presupuesto revisado', data: grupos.map(g => g.presupuesto_revisado), backgroundColor: theme.green,  borderRadius: 4, maxBarThickness: 26 },
          { label: 'Costo acumulado real', data: grupos.map(g => g.costo_acumulado),      backgroundColor: theme.gold,   borderRadius: 4, maxBarThickness: 26 },
        ],
      }}
      options={rgBaseOptions(theme, { money: true, legend: true })}/>
  );
}

function RiaSobreejercicioChart({ rows, theme, flagC }) {
  if (!rows || !rows.length) {
    return <div style={{ padding: 28, textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5 }}>Ninguna clave presupuestada excede su presupuesto por ahora.</div>;
  }
  const top = rows.slice(0, 12);
  const options = {
    indexAxis: 'y',
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
      legend: { display: false },
      tooltip: {
        backgroundColor: theme.ink, titleColor: '#fff', bodyColor: '#fff',
        borderWidth: 0, padding: 10, cornerRadius: 8,
        titleFont: { family: theme.font, weight: '600' }, bodyFont: { family: theme.mono },
        callbacks: { label: (c) => 'Sobre-ejercicio: $' + (Number(c.parsed.x) || 0).toLocaleString('es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) },
      },
    },
    scales: {
      x: { grid: { color: theme.line, drawTicks: false }, border: { display: false }, ticks: { color: theme.muted, font: { family: theme.mono, size: 10 }, callback: (v) => rgMoneyShort(v) } },
      y: { grid: { display: false }, border: { color: theme.line }, ticks: { color: theme.muted, font: { family: theme.font, size: 10.5 } } },
    },
  };
  return (
    <RgChart type="bar" height={Math.max(180, top.length * 30)}
      data={{
        labels: top.map(c => c.clave),
        datasets: [{
          data: top.map(c => Math.round((c.gasto - c.presupuestado) * 100) / 100),
          backgroundColor: top.map(c => {
            const ratio = c.presupuestado > 0 ? c.gasto / c.presupuestado : 0;
            return ratio >= 1.5 ? flagC.over : (ratio >= 1.1 ? flagC.alert : flagC.warn);
          }),
          borderRadius: 4, maxBarThickness: 18,
        }],
      }}
      options={options}/>
  );
}

// ── Vista principal ───────────────────────────────────────────────────────────
function ReporteIAView({ onNav, user, onLogout }) {
  const { data: proyectos } = useApiData('proyectos.php');
  const [pid, setPid] = useState(null);
  const [report, setReport] = useState(null);
  const [generating, setGenerating] = useState(false);
  const [verId, setVerId] = useState(null);
  const [debugMode, setDebugMode] = useState(false);
  const [debug, setDebug] = useState(null);   // respuesta de action=debug (paso a paso)

  // Asignación masiva de presupuesto para "claves con gasto real pero sin presupuesto"
  const [selSinPresu, setSelSinPresu] = useState({});   // { insumoid: true }
  const [montoSinPresu, setMontoSinPresu] = useState({}); // { insumoid: "1234.56" } — override editable
  const [bulkUmbral, setBulkUmbral] = useState(80);
  const [bulkFi, setBulkFi] = useState('');
  const [bulkFf, setBulkFf] = useState('');
  const [asignando, setAsignando] = useState(false);

  // Migración ÚNICA hacia presupuesto_insumo (Contraloría) — v6.0
  const [migOpen, setMigOpen] = useState(false);
  const [migLoading, setMigLoading] = useState(false);
  const [migItems, setMigItems] = useState(null);   // null = aún no cargado
  const [migIncluir, setMigIncluir] = useState({}); // "proyecto_id:insumo_id" -> bool
  const [migClave, setMigClave] = useState({});     // "proyecto_id:insumo_id" -> string editable
  const [migBusy, setMigBusy] = useState(false);
  const [migResultado, setMigResultado] = useState(null);

  const { data: historial, loading: histLoading, reload: reloadHist } = useApiData('reporte_ia.php', { action: 'historial', proyectoid: pid }, !pid);

  useEffect(() => {
    if (!pid && proyectos && proyectos.length) setPid(proyectos[0].id);
  }, [proyectos]);

  useEffect(() => { setReport(null); setSelSinPresu({}); setMontoSinPresu({}); setMigItems(null); setMigIncluir({}); setMigClave({}); setMigResultado(null); }, [pid]);

  // Al llegar el historial de un proyecto sin reporte mostrado, cargar el más reciente.
  useEffect(() => {
    if (!report && historial && historial.length) verReporte(historial[0].id);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [historial]);

  async function verReporte(id) {
    setVerId(id);
    try {
      const d = await apiFetch('reporte_ia.php', 'GET', null, { action: 'ver', id });
      setReport(d);
    } catch (e) { toast.error(e.message); }
    finally { setVerId(null); }
  }

  async function handleGenerar() {
    if (!pid) return;
    setGenerating(true);
    try {
      if (debugMode) {
        const d = await apiFetch('reporte_ia.php?action=debug', 'POST', { proyectoid: pid });
        setDebug(d);
        const fail = (d.steps || []).find(s => !s.ok);
        if (fail) toast.error('Diagnóstico: falló en “' + fail.label + '”');
        else toast.success('Diagnóstico completado — el reporte SÍ se guardó (revisa el paso a paso).');
        if (d.reporte_id) reloadHist();
        return;
      }
      setDebug(null);
      const d = await apiFetch('reporte_ia.php?action=generar', 'POST', { proyectoid: pid });
      setReport(d);
      if (d.insuficiente) toast.info('Este proyecto aún no tiene gasto real registrado para analizar.');
      else toast.success('Reporte generado — calificación ' + d.analisis_ia.calificacion_presupuesto.score + '/100');
      reloadHist();
    } catch (e) { toast.error(e.message); }
    finally { setGenerating(false); }
  }

  function toggleSelSinPresu(insumoid, gasto) {
    setSelSinPresu(prev => {
      const next = { ...prev };
      if (next[insumoid]) delete next[insumoid]; else next[insumoid] = true;
      return next;
    });
    setMontoSinPresu(prev => prev[insumoid] != null ? prev : { ...prev, [insumoid]: String(gasto) });
  }

  function toggleSelTodasSinPresu(rows) {
    const todasSeleccionadas = rows.length > 0 && rows.every(c => selSinPresu[c.insumoid]);
    if (todasSeleccionadas) { setSelSinPresu({}); return; }
    const next = {}; const montos = { ...montoSinPresu };
    rows.forEach(c => { next[c.insumoid] = true; if (montos[c.insumoid] == null) montos[c.insumoid] = String(c.gasto); });
    setSelSinPresu(next);
    setMontoSinPresu(montos);
  }

  async function handleAsignarPresupuestos(rows) {
    const seleccionadas = rows.filter(c => selSinPresu[c.insumoid]);
    if (!seleccionadas.length) { toast.error('Selecciona al menos una clave.'); return; }
    const items = seleccionadas.map(c => ({
      insumoid: c.insumoid,
      monto: c.tiene_limite_contraloria ? c.monto_contraloria : (parseFloat(montoSinPresu[c.insumoid]) || c.gasto),
      pct_umbral: Number(bulkUmbral) || 80,
      fecha_inicio: bulkFi || null,
      fecha_fin: bulkFf || null,
      descripcion: c.posible_duplicado ? `Detectado por Reporte IA — posible clave equivalente a ${c.posible_duplicado.clave}` : 'Detectado por Reporte IA (gasto real sin presupuesto)',
    }));
    setAsignando(true);
    try {
      const res = await apiFetch('presupuestos_proyecto.php?action=bulk', 'POST', { proyectoid: pid, items });
      toast.success(`Presupuesto asignado: ${res.creadas} nuevas, ${res.reactivadas} actualizadas${res.omitidas ? `, ${res.omitidas} omitidas` : ''}.`);
      const agregadas = new Set(seleccionadas.map(c => c.insumoid));
      setReport(r => r ? { ...r, datos_duros: { ...r.datos_duros, top_sin_presupuesto: r.datos_duros.top_sin_presupuesto.filter(c => !agregadas.has(c.insumoid)) } } : r);
      setSelSinPresu({});
    } catch (e) { toast.error(e.message); }
    finally { setAsignando(false); }
  }

  // ── Migración ÚNICA hacia presupuesto_insumo (Contraloría) — v6.0 ────────────
  function migKey(it) { return it.proyecto_id + ':' + it.insumo_id; }

  async function cargarMigracion() {
    if (!pid) return;
    setMigLoading(true);
    setMigResultado(null);
    try {
      const d = await apiFetch('presupuestos_proyecto.php', 'GET', null, { action: 'migrar_preview', proyectoid: pid });
      const items = d.items || [];
      setMigItems(items);
      const inc = {}; const cla = {};
      items.forEach(it => { const k = migKey(it); inc[k] = true; cla[k] = it.clave_grupo; });
      setMigIncluir(inc);
      setMigClave(cla);
      if (!items.length) toast.info('Sin filas pendientes — todas las alertas activas de este proyecto ya están en Contraloría.');
    } catch (e) { toast.error(e.message); }
    finally { setMigLoading(false); }
  }

  function migToggleTodos() {
    if (!migItems || !migItems.length) return;
    const todas = migItems.every(it => migIncluir[migKey(it)]);
    const next = {};
    migItems.forEach(it => { next[migKey(it)] = !todas; });
    setMigIncluir(next);
  }

  function migBuildPayload() {
    return (migItems || []).filter(it => migIncluir[migKey(it)]).map(it => ({
      proyecto_id: it.proyecto_id,
      insumo_id: it.insumo_id,
      clave: (migClave[migKey(it)] != null ? migClave[migKey(it)] : it.clave_grupo) || '',
      grupo: it.grupo,
      monto: it.monto,
      moneda: it.moneda || 'MXN',
      incluir: true,
    }));
  }

  async function migExportarCSV() {
    const items = migBuildPayload();
    if (!items.length) { toast.error('Selecciona al menos una fila.'); return; }
    setMigBusy(true);
    try {
      const d = await apiFetch('presupuestos_proyecto.php?action=migrar_commit', 'POST', { items, modo: 'exportar' });
      const blob = new Blob(['﻿' + d.csv], { type: 'text/csv;charset=utf-8;' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = 'migracion_contraloria_presupuesto_insumo.csv'; a.click();
      URL.revokeObjectURL(url);
      toast.success(`CSV generado con ${d.filas} fila(s).`);
    } catch (e) { toast.error(e.message); }
    finally { setMigBusy(false); }
  }

  async function migAplicarEnContraloria() {
    const items = migBuildPayload();
    if (!items.length) { toast.error('Selecciona al menos una fila.'); return; }
    setMigBusy(true);
    try {
      const d = await apiFetch('presupuestos_proyecto.php?action=migrar_commit', 'POST', { items, modo: 'aplicar' });
      setMigResultado(d);
      if (d.aplicadas > 0) toast.success(`Migradas ${d.aplicadas} fila(s) a Contraloría${d.ya_existian ? ` (${d.ya_existian} ya existían)` : ''}${d.sin_permiso ? ` — ${d.sin_permiso} con error` : ''}.`);
      else if (d.sin_permiso > 0) toast.error('No se pudo escribir en Contraloría — usa la exportación.');
      else toast.info(`Nada nuevo que aplicar (${d.ya_existian} ya existían).`);
      cargarMigracion();
    } catch (e) { toast.error(e.message); }
    finally { setMigBusy(false); }
  }

  const chartTheme = (typeof rgTheme === 'function') ? rgTheme() : {};
  const flagC = (typeof window !== 'undefined') ? riaFlagColors() : {};
  const dd = report && !report.insuficiente ? report.datos_duros : null;
  const ia = report && !report.insuficiente ? report.analisis_ia : null;
  const score = ia ? ia.calificacion_presupuesto.score : null;

  const proyectoActual = (proyectos || []).find(p => p.id === pid);

  return (
    <div className="rg-app">
      <Sidebar active="reporte_ia" onNav={onNav} alertCount={0} user={user} onLogout={onLogout}/>
      <main className="rg-main">
        <Topbar crumbs="Operación / Reporte IA" title="Reporte IA de presupuesto"
          actions={
            <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
              <select className="rg-select" value={pid || ''} onChange={e => setPid(Number(e.target.value))} style={{ minWidth: 260 }}>
                {(proyectos || []).map(p => <option key={p.id} value={p.id}>{p.clave} · {p.nombre}</option>)}
              </select>
              <label style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--rg-muted)' }} title="Muestra el paso a paso y, si falla al guardar, el error real de la base de datos">
                <input type="checkbox" checked={debugMode} onChange={e => setDebugMode(e.target.checked)}/> Modo diagnóstico
              </label>
              <button className="rg-btn primary" disabled={!pid || generating} onClick={handleGenerar}>
                {Icon.reporteia()} {generating ? (debugMode ? 'Diagnosticando…' : 'Generando…') : (debugMode ? 'Diagnosticar' : 'Generar Reporte IA')}
              </button>
            </div>
          }/>
        <div className="rg-content">

          {/* Migración ÚNICA hacia presupuesto_insumo (Contraloría) */}
          <div className="rg-card" style={{ marginBottom: 16 }}>
            <div className="rg-card-header" style={{ cursor: 'pointer' }} onClick={() => setMigOpen(o => !o)}>
              <div>
                <h3>{Icon.catalog(14)} Migración a Contraloría</h3>
                <div className="sub">Lleva las alertas de presupuesto ya capturadas aquí hacia presupuesto_insumo — herramienta de UNA sola vez, no un sincronizado continuo.</div>
              </div>
              <button className="rg-btn">{migOpen ? 'Ocultar' : 'Mostrar'}</button>
            </div>
            {migOpen && (
              <div style={{ padding: '4px 16px 16px' }}>
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 12, flexWrap: 'wrap' }}>
                  <button className="rg-btn primary" disabled={!pid || migLoading} onClick={cargarMigracion}>
                    {migLoading ? 'Cargando…' : 'Cargar propuesta de migración'}
                  </button>
                  {migItems && (
                    <span style={{ fontSize: 12, color: 'var(--rg-muted)' }}>
                      {migItems.length} fila(s) pendientes de migrar para {proyectoActual ? proyectoActual.nombre : 'este proyecto'}
                    </span>
                  )}
                </div>

                {migItems && migItems.length === 0 && (
                  <div style={{ padding: 20, textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5 }}>
                    Sin filas pendientes — todas las alertas activas de este proyecto ya están en Contraloría, o no hay alertas activas.
                  </div>
                )}

                {migItems && migItems.length > 0 && (
                  <>
                    <div style={{ overflowX: 'auto' }}>
                      <table className="rg-table" style={{ width: '100%' }}>
                        <thead>
                          <tr>
                            <th style={{ width: 30 }}>
                              <input type="checkbox" checked={migItems.every(it => migIncluir[migKey(it)])} onChange={migToggleTodos}/>
                            </th>
                            <th>Clave canónica</th>
                            <th>Grupo</th>
                            <th>Clave a usar en Contraloría</th>
                            <th>Descripción</th>
                            <th>Monto</th>
                          </tr>
                        </thead>
                        <tbody>
                          {migItems.map(it => {
                            const k = migKey(it);
                            return (
                              <tr key={k}>
                                <td><input type="checkbox" checked={!!migIncluir[k]} onChange={() => setMigIncluir(prev => ({ ...prev, [k]: !prev[k] }))}/></td>
                                <td className="rg-mono">{it.clave_canonica}</td>
                                <td className="rg-mono">{it.grupo}</td>
                                <td>
                                  <input className="rg-input rg-mono" type="text"
                                    value={migClave[k] != null ? migClave[k] : it.clave_grupo}
                                    onChange={e => setMigClave(prev => ({ ...prev, [k]: e.target.value }))}
                                    style={{ width: 110 }}/>
                                  {it.sin_match_grupo && (
                                    <div style={{ marginTop: 3, fontSize: 11, color: 'var(--rg-flag-warn)' }} title="Sin fila exacta en el catálogo de grupo de Contraloría — sugerida por coincidencia de descripción">
                                      ⚠ {it.clave_sugerida ? `sugerida (${it.match_score}% similar)` : 'sin coincidencia — revisa manualmente'}
                                    </div>
                                  )}
                                </td>
                                <td>{it.descripcion}</td>
                                <td className="num">{riaMoney(it.monto)}</td>
                              </tr>
                            );
                          })}
                        </tbody>
                      </table>
                    </div>

                    <div style={{ display: 'flex', gap: 10, marginTop: 14, justifyContent: 'flex-end' }}>
                      <button className="rg-btn" disabled={migBusy} onClick={migExportarCSV}>{migBusy ? 'Generando…' : 'Exportar CSV'}</button>
                      <button className="rg-btn primary" disabled={migBusy} onClick={migAplicarEnContraloria}>{migBusy ? 'Aplicando…' : 'Aplicar en Contraloría'}</button>
                    </div>

                    {migResultado && (
                      <div style={{ marginTop: 12, fontSize: 12.5, color: 'var(--rg-muted)' }}>
                        Último resultado: {migResultado.aplicadas} aplicadas · {migResultado.ya_existian} ya existían · {migResultado.sin_permiso} con error/sin permiso
                        {migResultado.errores && migResultado.errores.length > 0 && (
                          <details style={{ marginTop: 6 }}>
                            <summary style={{ cursor: 'pointer' }}>Ver detalle ({migResultado.errores.length})</summary>
                            <ul style={{ margin: '6px 0 0', paddingLeft: 18 }}>
                              {migResultado.errores.map((er, i) => <li key={i}>{er}</li>)}
                            </ul>
                          </details>
                        )}
                      </div>
                    )}
                  </>
                )}
              </div>
            )}
          </div>

          {/* Diagnóstico paso a paso */}
          {debug && (
            <div className="rg-card" style={{ marginBottom: 16, border: '2px solid var(--rg-flag-warn)' }}>
              <div className="rg-card-header">
                <div><h3>Diagnóstico paso a paso</h3><div className="sub">A diferencia del importador, este SÍ intenta guardar de verdad — es la única forma de ver el error real si falla el guardado.</div></div>
                <button className="rg-btn" onClick={() => setDebug(null)}>Cerrar</button>
              </div>
              <div style={{ padding: '4px 16px 16px', display: 'grid', gap: 10 }}>
                {(debug.steps || []).map((s, i) => (
                  <div key={i} style={{ border: '1px solid var(--rg-line-2)', borderRadius: 8, overflow: 'hidden' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: 'var(--rg-cream)', fontWeight: 600, fontSize: 13 }}>
                      <span style={{ width: 18, height: 18, borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 11, fontWeight: 700, background: s.ok ? 'var(--rg-flag-ok)' : 'var(--rg-flag-over)' }}>{s.ok ? '✓' : '!'}</span>
                      {i + 1}. {s.label}
                    </div>
                    {s.detail != null && (
                      <pre className="rg-mono" style={{ margin: 0, padding: '10px 12px', fontSize: 11, lineHeight: 1.5, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 360, overflow: 'auto' }}>
                        {typeof s.detail === 'string' ? s.detail : JSON.stringify(s.detail, null, 2)}
                      </pre>
                    )}
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Historial */}
          {pid && (historial && historial.length > 0) && (
            <div className="rg-card" style={{ marginBottom: 16 }}>
              <div className="rg-card-header">
                <div><h3>Historial de reportes</h3><div className="sub">{proyectoActual ? proyectoActual.nombre : ''} · más reciente primero</div></div>
              </div>
              <div style={{ overflowX: 'auto' }}>
                <table className="rg-table" style={{ width: '100%' }}>
                  <thead><tr><th>Fecha</th><th>Generado por</th><th>Modelo</th><th>Score</th><th></th></tr></thead>
                  <tbody>
                    {historial.map(h => (
                      <tr key={h.id} style={{ background: report && report.id === h.id ? 'var(--rg-cream)' : undefined }}>
                        <td>{h.generado_en}</td>
                        <td>{h.generado_por_nombre || '—'}</td>
                        <td className="rg-mono" style={{ fontSize: 11 }}>{h.modelo || '—'}</td>
                        <td>{h.score_calificacion != null ? <span style={{ fontWeight: 700, color: riaScoreColor(h.score_calificacion) }}>{h.score_calificacion}/100</span> : '—'}</td>
                        <td className="actions">
                          <button className="rg-btn" disabled={verId === h.id} onClick={() => verReporte(h.id)}>{Icon.eye(13)} Ver</button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}

          {/* Estado vacío: sin historial ni reporte */}
          {pid && !histLoading && (!historial || historial.length === 0) && !report && (
            <div className="rg-card" style={{ padding: '40px 24px', textAlign: 'center' }}>
              <div style={{ fontSize: 14, color: 'var(--rg-muted)', marginBottom: 14 }}>
                Aún no se ha generado ningún Reporte IA para {proyectoActual ? <strong>{proyectoActual.nombre}</strong> : 'este proyecto'}.
              </div>
              <button className="rg-btn primary" disabled={generating} onClick={handleGenerar}>
                {Icon.reporteia()} {generating ? 'Generando…' : 'Generar el primero'}
              </button>
            </div>
          )}

          {/* Datos insuficientes */}
          {report && report.insuficiente && (
            <div className="rg-card" style={{ padding: '28px 24px', textAlign: 'center' }}>
              <div style={{ fontSize: 14, color: 'var(--rg-muted)', maxWidth: 560, margin: '0 auto' }}>
                Este proyecto todavía no tiene gasto real registrado (órdenes de compra pagadas o históricas importadas).
                En cuanto haya compras registradas, genera el reporte de nuevo para que la IA tenga algo que analizar.
              </div>
            </div>
          )}

          {/* Reporte completo */}
          {dd && ia && (
            <>
              <div style={{ fontSize: 11.5, color: 'var(--rg-muted)', marginBottom: 10 }}>
                Generado el {report.generado_en} · modelo {report.modelo} · confianza de la IA en los datos: <strong>{ia.nivel_confianza_datos}</strong>
              </div>

              {/* Cobertura de datos */}
              <div className="rg-card" style={{ padding: '10px 16px', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5, color: 'var(--rg-muted)' }}>
                {Icon.filter(13)}
                {dd.cobertura.claves_con_presupuesto} de {dd.cobertura.claves_con_compra} claves con compras registradas tienen presupuesto asignado ({dd.cobertura.pct}%) —
                el resto son datos que aún faltan por completar. El análisis mejora conforme se agreguen.
              </div>

              {/* KPIs */}
              <div className="rg-kpi-grid" style={{ gridTemplateColumns: 'repeat(5, 1fr)' }}>
                <RiaKpi label="Presupuesto total" value={riaMoney(dd.presupuesto_total)} sub="ADMINISTRADOR DE PROYECTOS"/>
                <RiaKpi label="Gasto real total" value={riaMoney(dd.gasto_total)} sub="pagado + histórico importado"/>
                <RiaKpi label="Cobertura de datos" value={dd.cobertura.pct + '%'} sub={`${dd.cobertura.claves_con_presupuesto}/${dd.cobertura.claves_con_compra} claves`}/>
                <RiaKpi label="Calificación IA" value={score + '/100'} valueColor={riaScoreColor(score)} sub="qué tan bien se presupuestó"/>
                <RiaKpi label="Propuesta global IA" value={riaMoney(ia.propuesta_global.monto_sugerido)} valueColor="var(--rg-gold)" sub="estimado — no es dato oficial"/>
              </div>

              {/* Gráficas */}
              <div className="rg-chart-row">
                <div className="rg-card">
                  <div className="rg-card-header"><div><h3>Presupuesto vs. costo real por grupo</h3><div className="sub">Proyección de Costos</div></div></div>
                  <div style={{ padding: '14px 16px 16px' }}><RiaGruposChart grupos={dd.grupos} theme={chartTheme}/></div>
                </div>
                <div className="rg-card">
                  <div className="rg-card-header"><div><h3>Claves que más sangran el presupuesto</h3><div className="sub">Gasto real − presupuestado, mayor a menor</div></div></div>
                  <div style={{ padding: '14px 16px 16px' }}><RiaSobreejercicioChart rows={dd.top_sobreejercicio} theme={chartTheme} flagC={flagC}/></div>
                </div>
              </div>

              {/* Claves con gasto pero sin presupuesto */}
              <div className="rg-card" style={{ marginTop: 16 }}>
                <div className="rg-card-header"><div><h3>Claves con gasto real pero sin presupuesto asignado</h3><div className="sub">Huecos de datos a completar — no es que estén "mal", es que faltan por presupuestar. Selecciona y asígnales presupuesto en masa para que no se queden olvidadas.</div></div></div>
                {(!dd.top_sin_presupuesto || dd.top_sin_presupuesto.length === 0) ? (
                  <div style={{ padding: 24, textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5 }}>Todas las claves con gasto ya tienen presupuesto asignado.</div>
                ) : (
                  <>
                    <div style={{ padding: '10px 16px', display: 'flex', gap: 14, alignItems: 'flex-end', flexWrap: 'wrap', borderBottom: '1px solid var(--rg-line)' }}>
                      <div className="rg-field">
                        <label style={{ fontSize: 10.5 }}>Umbral %</label>
                        <input className="rg-input rg-mono" type="number" min="1" max="100" value={bulkUmbral} onChange={e => setBulkUmbral(e.target.value)} style={{ width: 70 }}/>
                      </div>
                      <div className="rg-field">
                        <label style={{ fontSize: 10.5 }}>Fecha inicio (opcional, masiva)</label>
                        <input className="rg-input" type="date" value={bulkFi} onChange={e => setBulkFi(e.target.value)}/>
                      </div>
                      <div className="rg-field">
                        <label style={{ fontSize: 10.5 }}>Fecha fin (opcional, masiva)</label>
                        <input className="rg-input" type="date" value={bulkFf} onChange={e => setBulkFf(e.target.value)}/>
                      </div>
                      <button className="rg-btn primary" disabled={asignando || !Object.keys(selSinPresu).length} onClick={() => handleAsignarPresupuestos(dd.top_sin_presupuesto)} style={{ marginLeft: 'auto' }}>
                        {asignando ? 'Asignando…' : `Asignar presupuesto (${Object.keys(selSinPresu).length})`}
                      </button>
                    </div>
                    <div style={{ overflowX: 'auto' }}>
                      <table className="rg-table" style={{ width: '100%' }}>
                        <thead>
                          <tr>
                            <th style={{ width: 30 }}>
                              <input type="checkbox" checked={dd.top_sin_presupuesto.length > 0 && dd.top_sin_presupuesto.every(c => selSinPresu[c.insumoid])} onChange={() => toggleSelTodasSinPresu(dd.top_sin_presupuesto)}/>
                            </th>
                            <th>Clave</th><th>Descripción</th><th>Familia</th><th>Gasto real</th><th>Monto a presupuestar (MXN)</th>
                          </tr>
                        </thead>
                        <tbody>
                          {dd.top_sin_presupuesto.map(c => (
                            <tr key={c.insumoid}>
                              <td><input type="checkbox" checked={!!selSinPresu[c.insumoid]} onChange={() => toggleSelSinPresu(c.insumoid, c.gasto)}/></td>
                              <td className="rg-mono">{c.clave}</td>
                              <td>
                                {c.descripcion}
                                {c.posible_duplicado && (
                                  <div style={{ marginTop: 3, fontSize: 11, color: 'var(--rg-flag-warn)' }} title="Coincidencia por descripción — revisa si fue un error de captura en la Orden de Compra">
                                    ⚠ ¿Quisiste decir <strong className="rg-mono">{c.posible_duplicado.clave}</strong> · {c.posible_duplicado.descripcion} ({Math.round(c.posible_duplicado.score * 100)}% similar)?
                                  </div>
                                )}
                              </td>
                              <td>{c.familia}</td>
                              <td className="num">{riaMoney(c.gasto)}</td>
                              <td>
                                {c.tiene_limite_contraloria ? (
                                  <>
                                    <input className="rg-input rg-mono" type="text" disabled
                                      value={riaMoney(c.monto_contraloria)}
                                      style={{ width: 130 }}/>
                                    <div style={{ marginTop: 3 }}>
                                      <span className="rg-alert-tag ok" style={{ fontSize: 10 }}>Definido en Contraloría</span>
                                    </div>
                                  </>
                                ) : (
                                  <input className="rg-input rg-mono" type="number" step="0.01" disabled={!selSinPresu[c.insumoid]}
                                    value={montoSinPresu[c.insumoid] != null ? montoSinPresu[c.insumoid] : c.gasto}
                                    onChange={e => setMontoSinPresu(prev => ({ ...prev, [c.insumoid]: e.target.value }))}
                                    style={{ width: 130 }}/>
                                )}
                              </td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  </>
                )}
              </div>

              {/* Resumen ejecutivo */}
              <div className="rg-card" style={{ marginTop: 16, padding: '18px 20px' }}>
                <h3 style={{ margin: '0 0 10px' }}>Resumen ejecutivo</h3>
                {ia.resumen_ejecutivo.split(/\n\s*\n/).map((p, i) => (
                  <p key={i} style={{ margin: '0 0 10px', lineHeight: 1.6, fontSize: 13.5, color: 'var(--rg-ink)' }}>{p}</p>
                ))}
              </div>

              {/* Claves de riesgo */}
              <div className="rg-card" style={{ marginTop: 16 }}>
                <div className="rg-card-header"><div><h3>Claves de riesgo</h3><div className="sub">Según el análisis de la IA sobre los datos reales</div></div></div>
                {ia.claves_riesgo.length === 0 ? (
                  <div style={{ padding: 24, textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5 }}>La IA no identificó claves de riesgo con los datos disponibles.</div>
                ) : (
                  <div style={{ overflowX: 'auto' }}>
                    <table className="rg-table" style={{ width: '100%' }}>
                      <thead><tr><th>Clave</th><th>Descripción</th><th>Severidad</th><th>Presupuestado</th><th>Gasto real</th><th>Motivo</th><th>Recomendación</th></tr></thead>
                      <tbody>
                        {ia.claves_riesgo.map((r, i) => (
                          <tr key={i}>
                            <td className="rg-mono">{r.clave}</td>
                            <td>{r.descripcion}</td>
                            <td><RiaSevTag sev={r.severidad}/></td>
                            <td className="num">{r.presupuestado != null ? riaMoney(r.presupuestado) : '—'}</td>
                            <td className="num">{riaMoney(r.gasto)}</td>
                            <td style={{ maxWidth: 220 }}>{r.motivo}</td>
                            <td style={{ maxWidth: 220 }}>{r.recomendacion}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                )}
              </div>

              {/* Oportunidades de eficiencia */}
              <div className="rg-card" style={{ marginTop: 16, padding: '18px 20px' }}>
                <h3 style={{ margin: '0 0 12px' }}>Oportunidades de eficiencia</h3>
                {ia.oportunidades_eficiencia.length === 0 ? (
                  <div style={{ textAlign: 'center', color: 'var(--rg-muted)', fontSize: 12.5, padding: '12px 0' }}>Sin oportunidades identificadas con los datos disponibles.</div>
                ) : ia.oportunidades_eficiencia.map((o, i) => (
                  <div key={i} style={{ padding: '10px 0', borderTop: i > 0 ? '1px solid var(--rg-line)' : 'none' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 10 }}>
                      <strong className="rg-mono" style={{ fontSize: 12.5 }}>{o.clave}</strong>
                      <span style={{ fontSize: 11, color: 'var(--rg-muted)' }}>{o.descripcion}</span>
                    </div>
                    <div style={{ marginTop: 4, fontSize: 13 }}>{o.hallazgo}</div>
                    <div style={{ marginTop: 4, fontSize: 12.5, color: 'var(--rg-green-700)' }}>→ {o.accion_sugerida}</div>
                  </div>
                ))}
              </div>

              {/* Propuesta global + Calificación */}
              <div className="rg-chart-row" style={{ marginTop: 16 }}>
                <div className="rg-card" style={{ padding: '18px 20px', border: '1px solid var(--rg-gold)' }}>
                  <div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--rg-gold)' }}>
                    Propuesta global · Estimado por IA — no es un dato oficial
                  </div>
                  <div style={{ fontSize: 28, fontWeight: 800, marginTop: 8 }}>{riaMoney(ia.propuesta_global.monto_sugerido)}</div>
                  <p style={{ marginTop: 10, fontSize: 13, lineHeight: 1.6 }}>{ia.propuesta_global.justificacion}</p>
                  {ia.propuesta_global.supuestos && (
                    <div style={{ marginTop: 8, fontSize: 12, color: 'var(--rg-muted)' }}><strong>Supuestos:</strong> {ia.propuesta_global.supuestos}</div>
                  )}
                </div>

                <div className="rg-card" style={{ padding: '18px 20px' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                    <div style={{ fontSize: 32, fontWeight: 800, color: riaScoreColor(score) }}>{score}<span style={{ fontSize: 15, color: 'var(--rg-muted)' }}>/100</span></div>
                    <div style={{ fontSize: 12.5, color: 'var(--rg-muted)' }}>Calificación del presupuesto original</div>
                  </div>
                  <p style={{ marginTop: 10, fontSize: 13, lineHeight: 1.6 }}>{ia.calificacion_presupuesto.explicacion}</p>
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 10 }}>
                    <div>
                      <div style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--rg-flag-ok)' }}>A favor</div>
                      <ul style={{ margin: '6px 0 0', paddingLeft: 18, fontSize: 12.5 }}>
                        {ia.calificacion_presupuesto.factores_positivos.map((f, i) => <li key={i}>{f}</li>)}
                      </ul>
                    </div>
                    <div>
                      <div style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--rg-flag-over)' }}>En contra</div>
                      <ul style={{ margin: '6px 0 0', paddingLeft: 18, fontSize: 12.5 }}>
                        {ia.calificacion_presupuesto.factores_negativos.map((f, i) => <li key={i}>{f}</li>)}
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </>
          )}

        </div>
      </main>
    </div>
  );
}

Object.assign(window, { ReporteIAView });
