// ─────────────────────────────────────────────────────
// INC-011 — Costes de materiales por proyecto y proveedor.
//   · CostesPanel: pestaña «Costes» del expediente (y de la ficha de proyecto
//     de Programación): TOTAL COSTE y desglose por proveedor (lista + donut).
//     Feedback de Juanjo: lo que importa es el total y el reparto por
//     proveedor; real/estimado y la tabla de artículos van en el plegable
//     «Ver detalle por artículo» (plegado por defecto).
//   · CostesView: vista global (Operaciones › Costes de proyectos): total y
//     coste de cada expediente/proyecto en barras apiladas por proveedor.
// Coste real = líneas de OC (precio de la OC); estimado = líneas de materiales
// aún sin OC, al precio de referencia del artículo. Ver src/services/costes.js.
// Solo para quien tiene Compras u Órdenes (gate /api/costes en src/app.js).
// ─────────────────────────────────────────────────────

// Formato propio: es-ES no agrupa los miles con 4 cifras («1134,00»); aquí
// siempre «1.134,00». decMin/decMax = decimales mínimos/máximos.
function fmtNumEs(v, decMin, decMax) {
  const n = Number(v || 0);
  const neg = n < 0;
  let [ent, dec = ''] = Math.abs(n).toFixed(decMax).split('.');
  while (dec.length > decMin && dec.endsWith('0')) dec = dec.slice(0, -1);
  ent = ent.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
  return `${neg ? '-' : ''}${ent}${dec ? `,${dec}` : ''}`;
}
const fmtCoste = (v) => `${fmtNumEs(v, 2, 2)} €`;
const fmtCant = (v) => (v == null ? '—' : fmtNumEs(v, 0, 3));

// Mismo criterio que el gate del backend: compras u órdenes (admin y '*' pasan).
function puedeVerCostes() {
  const u = (window.API && API.getUser && API.getUser()) || {};
  if (u.rol === 'admin') return true;
  const eff = (Array.isArray(u.permisosEfectivos) && u.permisosEfectivos.length) ? u.permisosEfectivos : (u.permisos || []);
  return eff.includes('*') || eff.includes('compras') || eff.includes('ordenes');
}
window.puedeVerCostes = puedeVerCostes;

// Paleta categórica (modo claro). El color depende SOLO del proveedor (no de su
// posición en la lista), para que sea el mismo en el expediente, el proyecto,
// el panel de detalle y la vista global: proveedor_id sobre la paleta; sin id,
// hash del nombre. «Sin proveedor» va en gris.
const COSTE_COLORES = ['#2563eb', '#ea580c', '#16a34a', '#9333ea', '#dc2626', '#0891b2', '#ca8a04', '#db2777', '#4f46e5'];
const COSTE_OTROS = '#9aa0a8';
const COSTE_LEYENDA_MAX = 12;
const provKey = (p) => (p.proveedor_id ? `p${p.proveedor_id}` : `t${String(p.proveedor_nombre || '').toUpperCase()}`);
function colorProveedor(p) {
  if (p.proveedor_id) return COSTE_COLORES[Number(p.proveedor_id) % COSTE_COLORES.length];
  const nombre = String(p.proveedor_nombre || '').trim().toUpperCase();
  if (!nombre || nombre === 'SIN PROVEEDOR') return COSTE_OTROS;
  let h = 0;
  for (let i = 0; i < nombre.length; i++) h = (h * 31 + nombre.charCodeAt(i)) >>> 0;
  return COSTE_COLORES[h % COSTE_COLORES.length];
}

// ── Donut SVG ──
const CosteDonut = ({ items, total, size = 180 }) => {
  const r = 70, c = 2 * Math.PI * r;
  let acc = 0;
  const segs = items.filter((i) => i.value > 0);
  return (
    <svg width={size} height={size} viewBox="0 0 180 180" role="img" aria-label="Coste por proveedor">
      <circle cx="90" cy="90" r={r} fill="none" stroke="var(--surface-3)" strokeWidth="26" />
      {total > 0 && segs.map((s) => {
        const len = (s.value / total) * c;
        const el = (
          <circle key={s.key} cx="90" cy="90" r={r} fill="none" stroke={s.color} strokeWidth="26"
            strokeDasharray={`${Math.max(len - 1.5, 0.5)} ${c}`} strokeDashoffset={-acc}
            transform="rotate(-90 90 90)">
            <title>{`${s.label}: ${fmtCoste(s.value)} (${Math.round((s.value / total) * 100)} %)`}</title>
          </circle>
        );
        acc += len;
        return el;
      })}
      <text x="90" y="84" textAnchor="middle" style={{ fontSize: 10, fill: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '.06em', fontWeight: 600 }}>Total coste</text>
      <text x="90" y="104" textAnchor="middle" style={{ fontSize: 15, fill: 'var(--ink)', fontWeight: 700, fontFamily: 'var(--font-mono)' }}>
        {fmtNumEs(total, 0, 0)} €
      </text>
    </svg>
  );
};

// TOTAL COSTE como protagonista; real / estimado / sin precio, en pequeño.
const CosteHero = ({ total, real, estimado, sinPrecio, lineas, conEstimado = true }) => (
  <div className="coste-hero">
    <div>
      <div className="coste-hero-lbl">Total coste</div>
      <div className="coste-hero-num">{fmtCoste(total)}</div>
    </div>
    <div className="coste-hero-sub">
      {conEstimado && estimado > 0
        ? <span title="Real = líneas de orden de compra, al precio de la OC. Estimado = material aún sin OC, al precio de referencia del artículo.">Real (OC) <b>{fmtCoste(real)}</b> · estimado sin OC <b>{fmtCoste(estimado)}</b></span>
        : <span>Precio de las órdenes de compra</span>}
      {sinPrecio > 0 && <span style={{ color: 'var(--err)', marginLeft: 10 }} title="Estas líneas no suman: falta el precio en la OC o en el artículo">{sinPrecio}{lineas != null ? ` de ${lineas}` : ''} sin precio</span>}
    </div>
  </div>
);

const abrirOc = (id) => window.dispatchEvent(new CustomEvent('erp:open-orden', { detail: { id } }));

// ── Pestaña de costes de un expediente o proyecto ──
const CostesPanel = ({ expedienteId, proyectoId, onToast }) => {
  const [d, setD] = React.useState(null);
  const [err, setErr] = React.useState('');
  const idOk = (x) => /^\d+$/.test(String(x == null ? '' : x));
  const load = React.useCallback(() => {
    // Sin id válido (p. ej. al cerrar el drawer) no se pide nada.
    const url = idOk(expedienteId) ? `/api/costes/expediente/${expedienteId}`
      : idOk(proyectoId) ? `/api/costes/proyecto/${proyectoId}` : null;
    if (!url) return;
    setErr('');
    API.get(url).then(setD).catch((e) => { setErr(e.message || 'Error al cargar costes'); onToast && onToast(e.message || 'Error al cargar costes', true); });
  }, [expedienteId, proyectoId]);
  React.useEffect(() => { setD(null); load(); }, [load]);

  if (err) return <div className="muted" style={{ padding: 20, fontSize: 12.5 }}>{err}</div>;
  if (!d) return <div className="muted" style={{ padding: 20, fontSize: 12.5 }}>Cargando costes…</div>;

  const colorDe = colorProveedor;
  const conCoste = d.proveedores.filter((p) => p.total > 0);
  const reales = d.lineas.filter((l) => l.tipo === 'real');
  const estimadas = d.lineas.filter((l) => l.tipo === 'estimado');
  const maxProv = Math.max(1, ...conCoste.map((p) => p.total));

  const Seccion = ({ titulo, ayuda, rows, subtotal }) => (
    <>
      <tr className="coste-sec"><td colSpan={7}><b>{titulo}</b> <span className="muted">· {ayuda}</span></td></tr>
      {rows.length === 0 && <tr><td colSpan={7} className="muted" style={{ textAlign: 'center', padding: 12 }}>Sin líneas</td></tr>}
      {rows.map((l) => (
        <tr key={`${l.tipo}-${l.linea_id}`}>
          <td>
            {l.tipo === 'real'
              ? <button className="btn ghost sm" style={{ padding: '1px 6px' }} onClick={() => abrirOc(l.compra_id)} title={`Abrir OC · ${l.oc_estado || ''}`}>OC {l.oc_numero || l.compra_id}</button>
              : <span className="pill warn" title="Sin orden de compra: precio de referencia del artículo para ese proveedor">{l.de_stock ? 'De stock' : 'Estimado'}</span>}
          </td>
          <td><span className="coste-dot" style={{ background: colorDe(l) }} />{l.proveedor_nombre}</td>
          <td style={{ minWidth: 200 }}>
            {l.articulo || <span className="muted">(sin descripción)</span>}
            {(l.referencia || l.dimensiones) && <div className="muted" style={{ fontSize: 11 }}>{[l.referencia, l.dimensiones].filter(Boolean).join(' · ')}</div>}
          </td>
          <td className="num right">{fmtCant(l.cantidad)}</td>
          <td className="muted">{l.unidad || ''}</td>
          <td className="num right">{l.sin_precio ? <span className="pill err" title={l.tipo === 'real' ? 'La línea de la OC no tiene precio' : 'El artículo no tiene precio de referencia para este proveedor'}>sin precio</span> : fmtCoste(l.precio_unitario)}</td>
          <td className="num right strong">{l.sin_precio ? '—' : fmtCoste(l.importe)}</td>
        </tr>
      ))}
      {rows.length > 0 && (
        <tr className="coste-subtotal"><td colSpan={6} style={{ textAlign: 'right' }}>Subtotal {titulo.toLowerCase()}</td><td className="num right">{fmtCoste(subtotal)}</td></tr>
      )}
    </>
  );

  return (
    <div className="costes-panel">
      {d.ambito === 'expediente' && d.proyecto && (
        <div className="muted" style={{ fontSize: 12, marginBottom: 10 }}>Proyecto enlazado al expediente {d.expediente.numero}: se muestran los costes del expediente.</div>
      )}
      <CosteHero total={d.totales.total} real={d.totales.real} estimado={d.totales.estimado}
        sinPrecio={d.totales.sin_precio_real + d.totales.sin_precio_estimado} lineas={d.totales.lineas} />

      <div className="coste-resumen">
        <div className="coste-donut">
          <CosteDonut total={d.totales.total} items={conCoste.map((p) => ({ key: provKey(p), label: p.proveedor_nombre, value: p.total, color: colorDe(p) }))} />
        </div>
        <div className="coste-provs">
          <div className="coste-h">Coste por proveedor</div>
          {conCoste.length === 0 && <div className="muted" style={{ fontSize: 12.5 }}>Todavía no hay líneas con precio.</div>}
          {conCoste.map((p) => (
            <div key={provKey(p)} className="coste-prov">
              <span className="coste-dot" style={{ background: colorDe(p) }} />
              <span className="coste-prov-n" title={p.proveedor_nombre}>{p.proveedor_nombre}</span>
              <span className="coste-prov-bar">
                <span style={{ width: `${(p.total / maxProv) * 100}%`, background: colorDe(p) }} />
              </span>
              <span className="coste-prov-v">{fmtCoste(p.total)}</span>
            </div>
          ))}
          <div className="coste-prov coste-total">
            <span />
            <span className="coste-prov-n">TOTAL COSTE</span>
            <span />
            <span className="coste-prov-v">{fmtCoste(d.totales.total)}</span>
          </div>
        </div>
      </div>

      <details className="coste-detalle">
        <summary>Ver detalle por artículo <span className="muted" style={{ fontWeight: 400 }}>· {d.lineas.length} línea{d.lineas.length === 1 ? '' : 's'}</span></summary>
        <div className="coste-detalle-body">
          <div className="muted" style={{ fontSize: 12 }}>
            Real (órdenes de compra, precio de la OC): <b>{fmtCoste(d.totales.real)}</b> · Estimado (material aún sin OC, precio de referencia del artículo): <b>{fmtCoste(d.totales.estimado)}</b>
          </div>
          <div className="tbl-wrap">
            <div className="tbl-scroll" style={{ maxHeight: 'none' }}>
              <table className="tbl">
                <thead>
                  <tr>
                    <th>Origen</th><th>Proveedor</th><th>Artículo</th>
                    <th style={{ textAlign: 'right' }}>Cantidad</th><th>Ud.</th>
                    <th style={{ textAlign: 'right' }}>Coste unit.</th><th style={{ textAlign: 'right' }}>Total</th>
                  </tr>
                </thead>
                <tbody>
                  <Seccion titulo="Coste real" ayuda="órdenes de compra, precio de la OC" rows={reales} subtotal={d.totales.real} />
                  <Seccion titulo="Coste estimado" ayuda="materiales sin OC, precio de referencia" rows={estimadas} subtotal={d.totales.estimado} />
                  <tr className="coste-grantotal"><td colSpan={6} style={{ textAlign: 'right' }}>TOTAL COSTE</td><td className="num right">{fmtCoste(d.totales.total)}</td></tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </details>
    </div>
  );
};
window.CostesPanel = CostesPanel;

// ── Vista global: coste por expediente/proyecto, apilado por proveedor ──
const CostesView = ({ onToast }) => {
  const [desde, setDesde] = React.useState('');
  const [hasta, setHasta] = React.useState('');
  const [estado, setEstado] = React.useState('');
  const [estimado, setEstimado] = React.useState(true);
  const [verVacios, setVerVacios] = React.useState(false);
  const [search, setSearch] = React.useState('');
  const [d, setD] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [abierto, setAbierto] = React.useState(null);

  React.useEffect(() => {
    let alive = true;
    setLoading(true);
    const params = { estimado: estimado ? '1' : '0' };
    if (desde) params.desde = desde;
    if (hasta) params.hasta = hasta;
    if (estado) params.estado = estado;
    API.get('/api/costes/resumen', params)
      .then((r) => { if (alive) setD(r); })
      .catch((e) => onToast && onToast(e.message || 'Error al cargar costes', true))
      .finally(() => alive && setLoading(false));
    return () => { alive = false; };
  }, [desde, hasta, estado, estimado]);

  const colorDe = colorProveedor;
  const leyenda = d ? d.proveedores.filter((p) => p.total > 0) : [];
  const leyendaColor = leyenda.slice(0, COSTE_LEYENDA_MAX);
  const hayOtros = leyenda.length > COSTE_LEYENDA_MAX;

  const q = search.trim().toLowerCase();
  const filas = (d ? d.proyectos : [])
    .filter((p) => verVacios || p.totales.total > 0)
    .filter((p) => !q || `${p.numero || ''} ${p.nombre || ''} ${p.proveedores.map((x) => x.proveedor_nombre).join(' ')}`.toLowerCase().includes(q));
  const max = Math.max(1, ...filas.map((p) => p.totales.total));
  const tot = filas.reduce((a, p) => ({ real: a.real + p.totales.real, estimado: a.estimado + p.totales.estimado, total: a.total + p.totales.total }), { real: 0, estimado: 0, total: 0 });
  const sel = { padding: '4px 8px', border: '1px solid var(--line)', borderRadius: 4, background: 'var(--surface)', fontSize: 12.5 };

  return (
    <>
      <div className="page-h">
        <div>
          <h1>Costes de proyectos</h1>
          <div className="sub">Coste de materiales por expediente o proyecto, repartido por proveedor · {filas.length} proyecto{filas.length === 1 ? '' : 's'}</div>
        </div>
      </div>

      <CosteHero total={tot.total} real={tot.real} estimado={tot.estimado} conEstimado={estimado} />

      <div className="toolbar" style={{ flexWrap: 'wrap' }}>
        <div className="tb-search">
          <Icon name="search" />
          <input placeholder="Nº, cliente o proveedor…" value={search} onChange={(e) => setSearch(e.target.value)} />
        </div>
        <div className="tb-divider" />
        <span className="muted" style={{ fontSize: 12 }}>Fecha del proyecto</span>
        <input type="date" value={desde} onChange={(e) => setDesde(e.target.value)} title="Desde" style={sel} />
        <input type="date" value={hasta} onChange={(e) => setHasta(e.target.value)} title="Hasta" style={sel} />
        <select value={estado} onChange={(e) => setEstado(e.target.value)} style={sel}>
          <option value="">Todos los estados</option>
          <option value="abiertos">En curso</option>
          <option value="cerrados">Cerrados / terminados</option>
        </select>
        <label style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 12.5 }}>
          <input type="checkbox" checked={estimado} onChange={(e) => setEstimado(e.target.checked)} /> Incluir estimado
        </label>
        <label style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 12.5 }}>
          <input type="checkbox" checked={verVacios} onChange={(e) => setVerVacios(e.target.checked)} /> Ver proyectos sin precio
        </label>
        {(desde || hasta || estado || search) && (
          <button className="btn ghost" onClick={() => { setDesde(''); setHasta(''); setEstado(''); setSearch(''); }}><Icon name="x" size={12} /> Limpiar</button>
        )}
      </div>

      {leyenda.length > 0 && (
        <div className="coste-leyenda">
          {leyendaColor.map((p) => (
            <span key={provKey(p)}><span className="coste-dot" style={{ background: colorDe(p) }} />{p.proveedor_nombre} <b>{fmtCoste(p.total)}</b></span>
          ))}
          {hayOtros && <span className="muted" title={leyenda.slice(COSTE_LEYENDA_MAX).map((p) => p.proveedor_nombre).join(', ')}>+{leyenda.length - leyendaColor.length} proveedores más</span>}
        </div>
      )}

      {loading && <div style={{ padding: 40, textAlign: 'center', color: 'var(--ink-3)' }}>Cargando costes…</div>}
      {!loading && filas.length === 0 && (
        <div className="tbl-wrap" style={{ padding: 32, textAlign: 'center', color: 'var(--ink-3)', fontSize: 13 }}>
          No hay proyectos con coste para estos filtros. El coste sale de los precios de las órdenes de compra y, para lo aún no pedido, del precio de referencia del artículo.
        </div>
      )}
      {!loading && filas.length > 0 && (
        <div className="tbl-wrap coste-chart">
          {filas.map((p) => (
            <div key={p.grupo} className="coste-fila" onClick={() => setAbierto(p)} title="Ver el detalle de costes">
              <div className="coste-fila-n">
                <span className="mono">{p.numero || '—'}</span>
                <span className="coste-fila-cli">{p.nombre}</span>
                <span className={`pill ${p.tipo === 'expediente' ? 'glass' : ''}`} style={{ fontSize: 10 }}>{p.tipo === 'expediente' ? 'Expediente' : 'Programación'}</span>
              </div>
              <div className="coste-fila-bar">
                {p.proveedores.filter((x) => x.total > 0).map((x) => (
                  <span key={provKey(x)} style={{ width: `${(x.total / max) * 100}%`, background: colorDe(x) }} title={`${x.proveedor_nombre}: ${fmtCoste(x.total)}`} />
                ))}
              </div>
              <div className="coste-fila-v">
                {fmtCoste(p.totales.total)}
                {(p.totales.sin_precio_real + p.totales.sin_precio_estimado) > 0 && (
                  <small title="Líneas sin precio: no suman">{p.totales.sin_precio_real + p.totales.sin_precio_estimado} sin precio</small>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      {abierto && (
        <>
          <div className="drawer-bg open" onClick={() => setAbierto(null)} />
          <div className="drawer open exp-drawer">
            <div className="dr-head">
              <span className="id mono">{abierto.numero}</span>
              <h2 style={{ flex: 1, minWidth: 0 }}>Costes · {abierto.nombre}</h2>
              <div className="actions">
                {abierto.pedido_id && (
                  <button className="btn ghost sm" onClick={() => { const id = abierto.pedido_id; setAbierto(null); window.dispatchEvent(new CustomEvent('erp:open-expediente', { detail: { pedidoId: id } })); }}>
                    <Icon name="package" size={12} /> Abrir expediente
                  </button>
                )}
                <button className="icon-btn" onClick={() => setAbierto(null)}><Icon name="x" /></button>
              </div>
            </div>
            <div className="dr-body">
              <CostesPanel expedienteId={abierto.pedido_id} proyectoId={abierto.proyecto_id} onToast={onToast} />
            </div>
          </div>
        </>
      )}
    </>
  );
};
window.CostesView = CostesView;
