// =========================================================================
// INVENTARIO + DETALLE DE INMUEBLE
// =========================================================================

const PropCard = ({ p, onOpen, onEdit }) => {
  const { Icons, fmtEUR, DATA } = window;
  // La cuenta de fotos estaba a fuego en 12, en TODAS las tarjetas, tuviera el
  // inmueble fotos o no. Ahora es la de verdad, y si no hay no se enseña nada.
  const nFotos = ((DATA.DOCS_BY_PROPERTY || {})[p.id] || []).filter(d => d.esFoto).length;
  return (
    <div className="prop-card" onClick={() => onOpen(p.id)}>
      <div className="prop-photo">
        {nFotos > 0 ? "FOTO INMUEBLE" : "SIN FOTOS"}
        <div className="ph-overlay">
          <div className="ph-top">
            {p.cooling && <Pill tone="danger">FRÍO {p.days}d</Pill>}
            <span className="ph-derecha">
              {nFotos > 0 && <span className="ph-count"><Icons.Image size={12}/> {nFotos}</span>}
              {onEdit && p._uid && (
                <button
                  className="prop-editar"
                  title={"Editar " + p.ref}
                  aria-label={"Editar " + p.ref}
                  // La tarjeta entera abre la ficha: sin esto se abrirían las dos.
                  onClick={(e) => { e.stopPropagation(); onEdit(p._uid); }}
                >
                  <Icons.Edit size={12}/>
                </button>
              )}
            </span>
          </div>
          <div className="ph-bot">
            <div className="ph-price">{fmtEUR(p.price)}</div>
            <Pill tone="brand">{p.type}</Pill>
          </div>
        </div>
      </div>
      <div className="prop-body">
        <div className="prop-addr">{p.addr}</div>
        <div className="prop-loc"><Icons.MapPin/>{p.town}</div>
        <div className="prop-specs">
          {p.rooms > 0 && <span className="prop-spec"><Icons.Bed/>{p.rooms} dorm</span>}
          {p.baths > 0 && <span className="prop-spec"><Icons.Bath/>{p.baths} baño</span>}
          <span className="prop-spec"><Icons.Sqm/>{p.area} m²</span>
        </div>
        <div className="prop-foot">
          <div className="prop-mgr"><div className="ava">{p.comercializador}</div>{p.captador !== p.comercializador && <><span style={{color: "var(--fg-4)"}}>+</span><div className="ava">{p.captador}</div></>}</div>
          <Pill tone={p.phase === "reserva" || p.phase === "arras" || p.phase === "firma" ? "success" : p.phase === "captacion" || p.phase === "registro" ? "info" : "warning"}>
            {window.DATA.PHASES.find(ph => ph.key === p.phase)?.short}
          </Pill>
        </div>
      </div>
    </div>
  );
};

const InventoryView = ({ onOpenProperty, onCreate, onEditProperty }) => {
  const { Icons, DATA, PageHeader, fmtEUR } = window;
  const [view, setView] = React.useState("table");
  const [search, setSearch] = React.useState("");
  const [estadoFilter, setEstadoFilter] = React.useState("all");
  const [tipoFilter, setTipoFilter] = React.useState("all");
  const [responsableFilter, setResponsableFilter] = React.useState("all");
  const [sortBy, setSortBy] = React.useState("ref-desc");

  // Estados únicos
  const allEstados = [...new Set((DATA.INMUEBLES || []).flatMap(p => p.estados || []))].sort();
  const tipos = [...new Set((DATA.INMUEBLES || []).map(p => p.typeKey).filter(Boolean))];
  const responsables = [...new Set((DATA.INMUEBLES || []).map(p => p.comercializador).filter(r => r && r !== "??"))];

  let list = DATA.INMUEBLES || [];
  if (search) {
    const s = search.toLowerCase();
    // Las referencias se comparan SIN guiones. Tras el renombrado por cajones,
    // quien lleva años escribiendo "26014" tiene que seguir encontrando el
    // inmueble, que hoy se llama VEN-26-014. `refAnterior` guarda además la
    // que tenía justo antes del último cambio de cajón.
    const soloAlnum = (t) => String(t || "").toLowerCase().replace(/[^a-z0-9]/g, "");
    const sRef = soloAlnum(search);
    list = list.filter(p =>
      (p.addr || "").toLowerCase().includes(s) ||
      (p.nombreCorto || "").toLowerCase().includes(s) ||
      (sRef && soloAlnum(p.ref).includes(sRef)) ||
      (sRef && soloAlnum(p.refAnterior).includes(sRef)) ||
      (p.town || "").toLowerCase().includes(s) ||
      (p.propietarioNombre || "").toLowerCase().includes(s) ||
      (p.compradorNombre || "").toLowerCase().includes(s)
    );
  }
  if (estadoFilter !== "all") {
    if (estadoFilter === "activos") list = list.filter(p => !p.isDespublicado && !p.isVendido);
    else if (estadoFilter === "cooling") list = list.filter(p => p.cooling);
    else list = list.filter(p => (p.estados || []).includes(estadoFilter));
  }
  if (tipoFilter !== "all") list = list.filter(p => p.typeKey === tipoFilter);
  if (responsableFilter !== "all") list = list.filter(p => p.comercializador === responsableFilter);

  list = [...list].sort((a, b) => {
    if (sortBy === "alphabetical") return (a.addr || "").localeCompare(b.addr || "", "es");
    if (sortBy === "ref-desc") return (b.ref || "").localeCompare(a.ref || "", "es");
    if (sortBy === "ref-asc") return (a.ref || "").localeCompare(b.ref || "", "es");
    if (sortBy === "area-desc") return b.area - a.area;
    if (sortBy === "year-desc") return (b.anoConstruccion || 0) - (a.anoConstruccion || 0);
    if (sortBy === "year-asc") return (a.anoConstruccion || 9999) - (b.anoConstruccion || 9999);
    return 0;
  });

  // Estado → tono de pill
  const tonePorEstado = (e) => {
    if (e === "Vendido") return "success";
    if (e === "Despublicado") return "neutral";
    if (e === "En venta" || e === "En alquiler" || e === "Alquiler piso completo" || e === "Alquiler por habitaciones") return "info";
    if (e === "Reforma") return "warning";
    if (e === "Reservado" || e === "Negociación") return "brand";
    if (e === "Demanda") return "danger";
    return "neutral";
  };

  return (
    <>
      <PageHeader
        eyebrow={`${(DATA.INMUEBLES || []).length} inmuebles · mostrando ${list.length}`}
        title="INMUEBLES"
        sub="Cartera completa: pisos, chalets, locales, parcelas y traspasos. Filtros multi-eje y orden personalizable."
        actions={<>
          <button className="btn secondary"><Icons.Download/> Exportar CSV</button>
          <button className="btn primary" onClick={onCreate}><Icons.Plus/> Alta de inmueble</button>
        </>}
      />

      <div style={{display: "flex", gap: 8, marginBottom: 12, flexWrap: "wrap", alignItems: "center"}}>
        <div className="tb-search" style={{width: 340, padding: "7px 12px"}}>
          <Icons.Search/>
          <input
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder="Dirección, referencia, propietario, comprador…"
            style={{border: "none", background: "transparent", outline: "none", fontFamily: "inherit", fontSize: 13, color: "var(--fg-1)", flex: 1}}
          />
        </div>

        <select className="select" style={{width: "auto", padding: "6px 26px 6px 10px"}} value={estadoFilter} onChange={e => setEstadoFilter(e.target.value)}>
          <option value="all">Todos los estados</option>
          <option value="activos">⚡ Activos (no vendidos)</option>
          <option value="cooling">🔥 En riesgo (&gt;14d)</option>
          <option disabled>───────────</option>
          {allEstados.map(s => <option key={s} value={s}>{s}</option>)}
        </select>

        <select className="select" style={{width: "auto", padding: "6px 26px 6px 10px"}} value={tipoFilter} onChange={e => setTipoFilter(e.target.value)}>
          <option value="all">Todos los tipos</option>
          {tipos.map(t => <option key={t} value={t}>{t.toUpperCase()}</option>)}
        </select>

        <select className="select" style={{width: "auto", padding: "6px 26px 6px 10px"}} value={responsableFilter} onChange={e => setResponsableFilter(e.target.value)}>
          <option value="all">Cualquier comercial</option>
          {responsables.map(r => <option key={r} value={r}>{r}</option>)}
        </select>

        <div style={{marginLeft: "auto", display: "flex", gap: 8, alignItems: "center"}}>
          <span style={{fontSize: 11, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: ".08em"}}>Orden:</span>
          <select className="select" style={{width: "auto", padding: "6px 26px 6px 10px"}} value={sortBy} onChange={e => setSortBy(e.target.value)}>
            <option value="ref-desc">Referencia ↓ (más reciente)</option>
            <option value="ref-asc">Referencia ↑</option>
            <option value="alphabetical">Dirección A–Z</option>
            <option value="area-desc">Superficie ↓</option>
            <option value="year-desc">Año construcción ↓</option>
            <option value="year-asc">Año construcción ↑</option>
          </select>
          <div className="view-tabs">
            <button className={view === "grid" ? "active" : ""} onClick={() => setView("grid")} title="Grid"><Icons.Grid/></button>
            <button className={view === "table" ? "active" : ""} onClick={() => setView("table")} title="Tabla"><Icons.List/></button>
          </div>
        </div>
      </div>

      {view === "grid" ? (
        <div className="inv-grid">
          {list.map(p => <PropCard key={p.id} p={p} onOpen={onOpenProperty} onEdit={onEditProperty}/>)}
          {list.length === 0 && (
            <div className="empty" style={{gridColumn: "1 / -1"}}>
              <div className="icon-wrap"><Icons.Building/></div>
              {/* Con la cartera vacía, "ajusta los filtros" manda a toquetear
                  unos filtros que nadie ha puesto. */}
              {(window.DATA.INMUEBLES || []).length === 0
                ? "Todavía no hay inmuebles en la cartera."
                : "Sin resultados. Ajusta los filtros."}
            </div>
          )}
        </div>
      ) : (
        <div className="tbl-wrap">
          <table className="tbl">
            <thead><tr>
              <th>Ref</th>
              <th>Dirección</th>
              <th>Tipo</th>
              <th>Estados</th>
              <th className="num">m²</th>
              <th className="num">Hab</th>
              <th className="num">Año</th>
              <th>Propietario</th>
              <th>Comprador</th>
              <th>Resp.</th>
              {/* Editar desde la lista: corregir un dato no deberia obligar a
                  entrar en la ficha y volver. */}
              <th className="num" style={{width: 44}}></th>
            </tr></thead>
            <tbody>
              {list.map(p => (
                <tr key={p.id} onClick={() => onOpenProperty(p.id)} className={p.cooling ? "cooling" : ""}>
                  <td><span className="code">{p.ref}</span></td>
                  <td>
                    <div style={{fontWeight: 600}}>{(p.addr || "—").length > 60 ? p.addr.slice(0, 60) + "…" : (p.addr || "—")}</div>
                    {p.town && p.town !== "—" && (
                      <div style={{fontSize: 11, color: "var(--fg-3)", marginTop: 2}}>{p.town}</div>
                    )}
                  </td>
                  <td><Pill tone="neutral">{p.type}</Pill></td>
                  <td>
                    <div style={{display: "flex", gap: 4, flexWrap: "wrap", maxWidth: 240}}>
                      {(p.estados || []).slice(0, 3).map((e, i) => (
                        <Pill key={i} tone={tonePorEstado(e)}>{e}</Pill>
                      ))}
                      {(p.estados || []).length > 3 && (
                        <span style={{fontSize: 10, color: "var(--fg-3)"}}>+{p.estados.length - 3}</span>
                      )}
                    </div>
                  </td>
                  <td className="num">{p.area > 0 ? p.area : "—"}</td>
                  <td className="num">{p.rooms > 0 ? p.rooms : "—"}</td>
                  <td className="num">{p.anoConstruccion || "—"}</td>
                  <td style={{fontSize: 12}}>
                    {p.propietarioNombre
                      ? <span>{p.propietarioNombre.length > 25 ? p.propietarioNombre.slice(0, 25) + "…" : p.propietarioNombre}</span>
                      : <span style={{color: "var(--fg-4)"}}>—</span>}
                  </td>
                  <td style={{fontSize: 12}}>
                    {p.compradorNombre
                      ? <span>{p.compradorNombre.length > 25 ? p.compradorNombre.slice(0, 25) + "…" : p.compradorNombre}</span>
                      : <span style={{color: "var(--fg-4)"}}>—</span>}
                  </td>
                  <td>
                    {p.comercializador && p.comercializador !== "??" ? (
                      <div className="kb-ava" style={{display: "inline-flex"}}>{p.comercializador}</div>
                    ) : <span style={{color: "var(--fg-4)"}}>—</span>}
                  </td>
                  <td className="num">
                    {onEditProperty && p._uid && (
                      <button
                        className="inv-editar"
                        title={"Editar " + p.ref}
                        aria-label={"Editar " + p.ref}
                        // La fila entera abre la ficha: sin esto, editar abriria las dos cosas.
                        onClick={(e) => { e.stopPropagation(); onEditProperty(p._uid); }}
                      >
                        <Icons.Edit/>
                      </button>
                    )}
                  </td>
                </tr>
              ))}
              {list.length === 0 && (
                <tr><td colSpan="11">
                  <div className="empty">
                    <div className="icon-wrap"><Icons.Building/></div>
                    {/* Con la cartera vacía, "ajusta los filtros" manda a toquetear
                        unos filtros que nadie ha puesto. */}
                    {(window.DATA.INMUEBLES || []).length === 0
                      ? "Todavía no hay inmuebles en la cartera."
                      : "Sin resultados. Ajusta los filtros."}
                  </div>
                </td></tr>
              )}
            </tbody>
          </table>
        </div>
      )}
    </>
  );
};

// ---------- FLIP CALCULATOR ----------
// B2 — Antes no recibía NI UNA PROP: arrancaba en 76.000 / 32.000 / 142.000 —los
// números de otro inmueble— y pintaba «ROI 22,5 %» en las 56 fichas, junto a datos
// reales. Ahora se precarga con lo que el inmueble TENGA y se queda VACÍA cuando
// no hay dato: sigue siendo una calculadora (los números los teclea el comercial),
// pero ya no afirma una proyección que nadie ha hecho.
// Sin entradas no hay resultados: los totales muestran «—», no un 0 € que se lee
// como una cuenta hecha.
const FlipCalculator = ({ compra = null, reforma: reformaIni = null, objetivo = null }) => {
  const { fmtEUR } = window;
  const [precio, setPrecio] = React.useState(compra);
  const [reforma, setReforma] = React.useState(reformaIni);
  const [venta, setVenta] = React.useState(objetivo);
  const num = (v) => (v == null || v === "" ? null : Number(v));
  const hayEntradas = num(precio) != null || num(reforma) != null || num(venta) != null;
  const p0 = num(precio) || 0, r0 = num(reforma) || 0, v0 = num(venta) || 0;
  const itp = Math.round(p0 * 0.08);
  const notaria = p0 ? 1800 : 0;
  const total = p0 + r0 + itp + notaria;
  // El MARGEN necesita las dos patas. Con solo el precio de compra, `0 - total`
  // daba «−136.800 € · −100,0 % de ROI»: una pérdida total afirmada porque falta
  // el precio de venta, no porque la operación vaya mal. La inversión (ITP,
  // notaría, total) sí se deriva solo de la compra, y esa sí se muestra.
  const puedeProyectar = num(venta) != null && total > 0;
  const margenBruto = puedeProyectar ? v0 - total : null;
  const margenPct = puedeProyectar ? ((margenBruto / total) * 100).toFixed(1) : null;
  const eur = (n) => (hayEntradas ? fmtEUR(n) : "—");
  const onNum = (set) => (e) => { const t = e.target.value.trim(); set(t === "" ? null : Math.max(0, Number(t) || 0)); };

  return (
    <div className="flip-calc">
      <div className="flip-row input-row">
        <div className="flip-lbl">Precio de compra</div>
        <input className="flip-input" type="number" placeholder="—" value={precio ?? ""} onChange={onNum(setPrecio)}/>
      </div>
      <div className="flip-row input-row">
        <div className="flip-lbl">Coste estimado reforma</div>
        <input className="flip-input" type="number" placeholder="—" value={reforma ?? ""} onChange={onNum(setReforma)}/>
      </div>
      <div className="flip-row input-row">
        <div className="flip-lbl">Precio de venta objetivo</div>
        <input className="flip-input" type="number" placeholder="—" value={venta ?? ""} onChange={onNum(setVenta)}/>
      </div>

      <div className="flip-row">
        <div className="flip-lbl">ITP estimado (8%)</div>
        <div className="flip-val">{eur(itp)}</div>
      </div>
      <div className="flip-row">
        <div className="flip-lbl">Notaría + registro</div>
        <div className="flip-val">{eur(notaria)}</div>
      </div>
      <div className="flip-row" style={{borderBottom: "none", paddingBottom: 0}}>
        <div className="flip-lbl" style={{fontWeight: 700, color: "var(--fg-1)"}}>Inversión total requerida</div>
        <div className="flip-val" style={{fontSize: 14}}>{eur(total)}</div>
      </div>

      <div className="flip-summary" style={{marginTop: 14}}>
        <div>
          <div className="out-lbl">Margen bruto</div>
          {/* Proyección, no contabilidad — pero el signo se lee igual. Sobre el
              negro de marca los tokens se rebindan a sus tintes oscuros
              (financial.css), así que la misma clase vale en ambos temas. */}
          <div className={"out-val " + (puedeProyectar ? window.finBalCls(margenBruto) : "")}>{puedeProyectar ? fmtEUR(margenBruto) : "—"}</div>
          <div className="out-sub">{margenPct == null ? "Falta el precio de venta objetivo" : margenPct + "% sobre inversión"}</div>
        </div>
        <div>
          <div className="out-lbl">ROI proyectado</div>
          <div className="out-val good">{margenPct == null ? "—" : margenPct + "%"}</div>
          <div className="out-sub">Plazo: 6-9 meses</div>
        </div>
      </div>
    </div>
  );
};

// ---------- PROPERTY DETAIL ----------
const PropertyDetail = ({ propId, onBack, onEdit }) => {
  const { Icons, DATA, PageHeader, fmtEUR, Card } = window;
  const p = DATA.INMUEBLES.find(x => x.id === propId) || DATA.INMUEBLES[0];
  // Sin fallback a la clave mock `FLIP_2025_034` (B2): hacía que un inmueble sin
  // documentos mostrara los de otro. `|| []` sí se queda: en LIVE la clave puede
  // no existir y sin el guard `docs.length` revienta la ficha entera.
  const docs = DATA.DOCS_BY_PROPERTY[p.id] || [];
  const phaseIdx = DATA.PHASES.findIndex(ph => ph.key === p.phase);

  // Movimientos vinculados a este inmueble — balance CALCULADO (contabilidad).
  const imTodos = (DATA.MOVIMIENTOS || []).filter(m => m.inmuebleUiId === p.id);
  const imBal = window.movBalance ? window.movBalance(imTodos) : { ingresos: 0, gastos: 0, balance: 0, balanceCobrado: 0, n: 0 };
  // LOS DOS PLANOS (CLAUDE.md §4): el Plano 1 se lista aparte y NO computa.
  const imMovs = imTodos.filter(m => !m.esOperacion);
  const imMovsOp = imTodos.filter(m => m.esOperacion);

  // Partes de visita FIRMADOS de este inmueble (bloque inmutable + notas).
  const [firmando, setFirmando] = React.useState(false);
  const [verVisitas, setVerVisitas] = React.useState(0); // refresco reload-less
  const [subiendoDoc, setSubiendoDoc] = React.useState(false);
  const [subiendoFoto, setSubiendoFoto] = React.useState(false);

  /**
   * Cambiar de cajón: CAP → VEN → ALQ → FLIP.
   *
   * Cambia el prefijo de la referencia conservando año y número, así que
   * `CAP-26-014` pasa a `VEN-26-014` y el inmueble sigue siendo "el 26014"
   * para quien lo llama así. Va con botón y no automático al cambiar de fase:
   * renombrar cambia cómo habla el equipo, y tiene que ser una decisión.
   */
  const CAJONES = [["CAP","Captación"],["VEN","Venta"],["ALQ","Alquiler"],["FLIP","Flip"]];
  const cajonActual = String(p.ref || "").split("-")[0];
  const [moviendo, setMoviendo] = React.useState(false);
  const [avisoCajon, setAvisoCajon] = React.useState(null);

  const moverDeCajon = async (cajon) => {
    if (moviendo || cajon === cajonActual) return;
    setAvisoCajon(null);
    setMoviendo(true);
    try {
      const r = await window.RevinSupabase.cambiarCajonDeInmueble(p._uid, cajon);
      if (!r.cambiado) { setAvisoCajon({ ok: true, texto: "Ya estaba en ese cajón." }); return; }
      // Se recarga entera: la referencia es la identidad de la ficha en la UI
      // (`codigo_largo || ref`), así que media aplicación la tiene apuntada.
      if (window.RevinData?.reload) await window.RevinData.reload();
      setAvisoCajon({ ok: true, texto: `Ahora es ${r.ref}. Antes era ${r.anterior}.` });
    } catch (e) {
      const msg = window.RevinSupabase.errorAmable ? window.RevinSupabase.errorAmable(e) : (e && e.message);
      setAvisoCajon({ ok: false, texto: String(msg) });
    } finally {
      setMoviendo(false);
    }
  };

  /**
   * Fotos del inmueble.
   *
   * Aqui habia cinco rectangulos grises con "FOTO PRINCIPAL", "SALON",
   * "COCINA", "DORMITORIO" y "BAÑO" escritos a mano, y un "+8 fotos" fijo.
   * Una maqueta: subieras las fotos que subieras, la ficha enseñaba lo mismo.
   *
   * Las URL se resuelven aparte porque no son inmediatas: las publicas
   * (`foto_portal`) son directas, pero las internas (`foto`) viven en un
   * bucket privado y hay que firmarlas, y eso es una llamada por foto.
   */
  const fotos = React.useMemo(() => docs.filter((d) => d.esFoto), [docs]);
  const clavesFotos = fotos.map((d) => d.path).join("|");
  const [urlFotos, setUrlFotos] = React.useState({});
  React.useEffect(() => {
    if (!fotos.length || !window.RevinSupabase) { setUrlFotos({}); return; }
    let vivo = true;
    (async () => {
      const pares = await Promise.all(fotos.map(async (d) => {
        try { return [d.path, await window.RevinSupabase.urlDocumento(d.path)]; }
        catch (_) { return [d.path, null]; }   // una foto rota no tumba la ficha
      }));
      if (vivo) setUrlFotos(Object.fromEntries(pares));
    })();
    return () => { vivo = false; };
  }, [clavesFotos]);
  const [errDoc, setErrDoc] = React.useState("");
  // La URL se pide EN EL CLIC, no al pintar la lista: así nunca se sirve un
  // enlace firmado ya caducado por tener la pestaña abierta un rato.
  const descargar = async (d) => {
    setErrDoc("");
    try { await window.RevinSupabase.descargarDocumento(d); }
    catch (e) { setErrDoc((e && e.message) || "No se ha podido abrir el documento."); }
  };
  // Recarga SOLO esta vista tras subir: `window.RevinData.reload()` subiría
  // `dataVersion` y App.jsx remontaría el view-stage entero, expulsando al
  // usuario al dashboard justo después de subir (CLAUDE.md §10).
  const trasSubirDoc = async () => {
    try {
      window.DATA = await window.RevinSupabase.loadDataFromSupabase();
      setVerVisitas(v => v + 1);
    } catch (e) { console.error(e); }
  };
  const visitasInm = (DATA.VISITS || []).filter(v => v.inmuebleUid === p._uid);

  return (
    <>
      {window.DemoDataBanner && <window.DemoDataBanner/>}
      <div className="page-h">
        <div>
          <button className="btn ghost xs" onClick={onBack} style={{marginBottom: 6, paddingLeft: 0}}><Icons.ChevronLeft/> Volver a inmuebles</button>
          <h1 style={{fontSize: 28}}>FICHA · {p.id}</h1>
          <div className="sub">{p.addr} · {p.town}</div>
        </div>
        <div className="actions">
          {/* Hasta hoy la ficha era de solo lectura y no habia NINGUNA forma de
              corregir un inmueble desde el CRM. Va la primera porque es lo que
              se busca cuando falta un dato. */}
          {onEdit && p._uid && (
            <button className="btn primary" onClick={() => onEdit(p._uid)}>
              <Icons.Edit/> Editar ficha
            </button>
          )}
          {p._uid && CAJONES.some(([c]) => c === cajonActual) && (
            <div className="inv-cajon">
              <span className="et">Cajón</span>
              {CAJONES.map(([c, nom]) => (
                <button
                  key={c}
                  type="button"
                  className={"inv-cajon-b" + (c === cajonActual ? " puesto" : "")}
                  aria-pressed={c === cajonActual}
                  disabled={moviendo}
                  title={c === cajonActual ? nom + " (el actual)" : "Pasar a " + nom.toLowerCase()}
                  onClick={() => moverDeCajon(c)}
                >{c}</button>
              ))}
            </div>
          )}
          <button className="btn secondary"><Icons.ExternalLink/> Ver en Idealista</button>
          <button className="btn secondary" onClick={() => setFirmando(true)}><Icons.Check/> Firmar parte de visita</button>
          <button className="btn secondary"><Icons.Sparkles/> Generar contrato</button>
          <button className="btn primary"><Icons.ArrowRight/> Avanzar fase</button>
        </div>
      </div>

      {avisoCajon && (
        <p className={"rv-resultado" + (avisoCajon.ok ? " ok" : "")} role="status" style={{marginBottom: 14}}>
          {avisoCajon.texto}
        </p>
      )}

      {/* Hero photos */}
      <div className="pd-hero" style={{marginBottom: 20}}>
        <div className="pd-photos">
          {fotos.length === 0 ? (
            <div className="pd-photo tall pd-sin-fotos">
              <span>Este inmueble no tiene fotos</span>
              <button className="btn secondary" onClick={() => setSubiendoFoto(true)}>
                <Icons.Upload/> Subir la primera
              </button>
            </div>
          ) : fotos.slice(0, 5).map((d, i) => (
            <div key={d.path} className={"pd-photo" + (i === 0 ? " tall" : "")}>
              {urlFotos[d.path]
                ? <img src={urlFotos[d.path]} alt={d.name} loading="lazy"/>
                : <span>{d.name}</span>}
              {d.tipo === "foto_portal" && <span className="pd-foto-etq">Portal</span>}
              {i === 4 && fotos.length > 5 && (
                <span className="badge-more">+{fotos.length - 5} fotos</span>
              )}
            </div>
          ))}
          {fotos.length > 0 && (
            <button className="pd-anadir-foto" onClick={() => setSubiendoFoto(true)}>
              <Icons.Plus/> Añadir
            </button>
          )}
        </div>
        <div className="pd-meta">
          <div className="pd-meta-top">
            <div className="pd-addr-block">
              <div className="eyebrow red" style={{marginBottom: 4}}>{p.type} · {DATA.PHASES.find(ph => ph.key === p.phase)?.label}</div>
              <h2 className="pd-addr">{p.addr}</h2>
              <div className="pd-loc">{p.town} · {p.area} m² · {p.rooms} dorm · {p.baths} baño</div>
              <div className="pd-id">{p.id}</div>
            </div>
            <div className="pd-prices">
              <div className="pd-price-lbl">Precio actual</div>
              <div className="pd-price-now">{fmtEUR(p.price)}</div>
              <div className="pd-price-tgt">Objetivo: {fmtEUR(p.target)}{p.price > 0 && p.target > 0 &&
                <span style={{color: "var(--fg-3)"}}> (+{Math.round((p.target - p.price) / p.price * 100)}%)</span>}</div>
            </div>
          </div>
          <div className="pd-kv-grid">
            <div className="kv"><div className="kv-lbl">Captador</div><div className="kv-val">{DATA.TEAM.find(t => t.id === p.captador)?.name || p.captador}</div></div>
            <div className="kv"><div className="kv-lbl">Comercializador</div><div className="kv-val">{DATA.TEAM.find(t => t.id === p.comercializador)?.name || p.comercializador}</div></div>
            <div className="kv"><div className="kv-lbl">En cartera</div><div className="kv-val">{p.days} días</div></div>
            <div className="kv"><div className="kv-lbl">Estado</div><div className="kv-val">{p.status}</div></div>
          </div>
        </div>
      </div>

      {/* Phase stepper */}
      <Card title="Avance en el Playbook" b={false} style={{marginBottom: 20}}>
        <div style={{padding: "16px 16px 20px"}}>
          <div className="pl-steps">
            {DATA.PHASES.map((ph, i) => (
              <div key={ph.key} className={"pl-step" + (i === phaseIdx ? " active" : "") + (i < phaseIdx ? " done" : "")}>
                <div className="pl-step-num">{i < phaseIdx ? "✓" : ph.num}</div>
                <div className="pl-step-lbl">{ph.short}</div>
              </div>
            ))}
          </div>
        </div>
      </Card>

      <div className="pd-grid">
        <div style={{display: "flex", flexDirection: "column", gap: 20}}>
          {/* Publishing status */}
          <Card title="Publicación en portales" b={false}>
            <div className="pub-list">
              {Object.entries(p.listings).map(([portal, info]) => (
                <div className="pub-row" key={portal}>
                  <div className={"pub-logo " + portal}>{portal === "web" ? "REVIN" : portal[0].toUpperCase()}</div>
                  <div>
                    <div className="pub-name">{portal === "idealista" ? "Idealista" : portal === "fotocasa" ? "Fotocasa" : "Web REVIN"}</div>
                    <div className="pub-sub">{info.live ? `Publicado desde ${info.since}` : "No publicado"}</div>
                  </div>
                  <div className="pub-stats">
                    {info.live ? <><span className="big">{info.leads}</span> leads</> : "—"}
                  </div>
                  <Pill tone={info.live ? "success" : "neutral"}>{info.live ? "Online" : "Offline"}</Pill>
                </div>
              ))}
            </div>
            <div style={{padding: "12px 16px", borderTop: "1px solid var(--border-1)", display: "flex", justifyContent: "space-between", alignItems: "center", background: "var(--bg-inset)"}}>
              <span style={{fontSize: 11, color: "var(--fg-2)"}}>Total leads acumulados:</span>
              <span style={{fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 700}}>{Object.values(p.listings).reduce((s, l) => s + (l.leads || 0), 0)} contactos · {p.days} días</span>
            </div>
          </Card>

          {/* Activity timeline */}
          <Card title="Historial de actividad" b={false}>
            <div className="activity">
              {DATA.ACTIVITY.map((a, i) => (
                <div className="act-item" key={i}>
                  <div className="act-rail"><div className={"act-dot " + a.tone}/></div>
                  <div className="act-body">
                    <div className="act-head">
                      <span className="who">{a.who}</span>
                      <span className="time">{a.time}</span>
                    </div>
                    <div className="act-text" dangerouslySetInnerHTML={{__html: a.text}}/>
                  </div>
                </div>
              ))}
            </div>
          </Card>

          {/* Documents */}
          <Card
            title={`Documentos · ${docs.length}`}
            right={<button className="btn xs primary" onClick={() => setSubiendoDoc(true)}><Icons.Upload/> Subir</button>}
            b={false}
          >
            {errDoc && (
              <div className="sb-login-err" style={{ margin: "10px 16px" }}><span>{errDoc}</span></div>
            )}
            {docs.map((d, i) => (
              <div className="doc" key={i}>
                <div className={"ico-doc " + (d.kind || "").toLowerCase()}>{d.kind || "DOC"}</div>
                <div className="doc-meta">
                  <div className="doc-name">{d.name}</div>
                  <div className="doc-sub"><span>{d.kind} · {d.size}</span><span>·</span><span>{d.date}</span></div>
                </div>
                <div className="doc-actions">
                  <button className="btn xs ghost" title="Descargar"
                          onClick={() => descargar(d)}><Icons.Download/></button>
                </div>
              </div>
            ))}
          </Card>

          {/* Contabilidad — movimientos vinculados a este inmueble.
              Solo para quien ve la caja: a un comercial, RLS le devuelve cero
              movimientos, y esta tarjeta pintaría cuatro ceros que se leen
              como "este inmueble no ha movido dinero". */}
          {window.veLaCaja() && <>
          <Card title={`Movimientos · ${imMovs.length}`} right={<Pill tone="neutral">BALANCE CALCULADO</Pill>} b={false}>
            <div style={{ display: "flex", gap: 28, padding: "12px 16px", background: "var(--bg-inset)", borderBottom: imMovs.length ? "1px solid var(--border-1)" : "none" }}>
              <div>
                <div className="kv-lbl">Ingresos</div>
                <div className="mono fin-amt fin-in">{fmtEUR(imBal.ingresos)}</div>
              </div>
              <div>
                <div className="kv-lbl">Gastos</div>
                <div className="mono fin-amt fin-out">{fmtEUR(imBal.gastos)}</div>
              </div>
              <div>
                <div className="kv-lbl">Balance</div>
                <div className={"mono fin-amt " + window.finBalCls(imBal.balance)}>{fmtEUR(imBal.balance)}</div>
              </div>
              {/* Caja real. Mismo verde que el ingreso a propósito (decisión
                  22/07/2026): dos verdes distintos se leían como ruido. */}
              <div>
                <div className="kv-lbl">Cobrado</div>
                <div className="mono fin-amt fin-cobrado">{fmtEUR(imBal.balanceCobrado)}</div>
              </div>
            </div>
            <window.MovimientosTable rows={imMovs} showVinculo={false} empty="Sin movimientos vinculados a este inmueble."/>
          </Card>

          {/* PLANO 1 — datos de la operación, no computan en el balance */}
          {imMovsOp.length > 0 && (
            <Card title={`Datos de la operación · ${imMovsOp.length}`} right={<Pill tone="neutral">NO COMPUTA EN BALANCE</Pill>} b={false}>
              <window.MovimientosTable rows={imMovsOp} showVinculo={false} empty="Sin datos de operación."/>
            </Card>
          )}
          </>}
        </div>

        <div style={{display: "flex", flexDirection: "column", gap: 20}}>
          {/* FLIP Calculator */}
          <Card title="Calculadora FLIP" right={<Pill tone="brand">Modelo REVIN</Pill>} b={false}>
            <FlipCalculator
              key={p.id}
              compra={p.precioCompra ?? null}
              reforma={p.costeReforma ?? null}
              objetivo={p.ventaObjetivo ?? null}
            />
          </Card>

          {/* Matching — B2. El bloque de candidatos se ha RETIRADO, no marcado:
              con los datos de hoy no se puede calcular ninguno. Falta el precio
              en los 56 inmuebles y `presupuesto_min` en los 168 clientes, y
              `zona` es texto libre con nombres de calle. El mejor matcher posible
              con lo que hay devuelve EL MISMO candidato en 50 de 56 fichas: eso
              no es un matcher, es el mock con otra cara. En su lugar, el hueco y
              qué falta para llenarlo. */}
          <Card title="Matching cliente-inmueble" b={false}>
            <div className="empty" style={{padding: "28px 20px"}}>
              <div className="icon-wrap"><Icons.Users/></div>
              <div style={{fontWeight: 700, marginBottom: 6}}>Sin candidatos que cruzar</div>
              <div style={{fontSize: 12.5, color: "var(--fg-3)", maxWidth: 320, margin: "0 auto", lineHeight: 1.5}}>
                El cruce necesita <b>precio del inmueble</b> y <b>presupuesto y zona del cliente</b>.
                Hoy faltan en la ficha y en la mayoría de contactos, así que no hay nada que comparar.
              </div>
            </div>
          </Card>

          {/* Partes de visita firmados (por inmueble) */}
          <Card title={`Partes de visita firmados · ${visitasInm.length}`} b={false}>
            {visitasInm.length === 0 ? (
              <div className="empty" style={{padding: 16}}>
                <span style={{fontSize: 12}}>Aún no hay partes firmados. Usa «Firmar parte de visita».</span>
              </div>
            ) : (
              <div style={{padding: 12}}>
                {visitasInm.map(v => (
                  <window.FirmaVisita.ParteCard key={v.id} visita={v} onSaved={() => setVerVisitas(x => x + 1)}/>
                ))}
              </div>
            )}
          </Card>
        </div>
      </div>

      {firmando && window.FirmaVisita && (
        <window.FirmaVisita.Modal
          inmueble={p}
          onClose={() => setFirmando(false)}
          onSaved={() => setVerVisitas(x => x + 1)}
        />
      )}

      {subiendoFoto && window.SubirDocumentoModal && (
        <window.SubirDocumentoModal
          inmuebleId={p._uid}
          tipoInicial="foto"
          onClose={() => setSubiendoFoto(false)}
          onSubido={trasSubirDoc}
        />
      )}

      {subiendoDoc && window.SubirDocumentoModal && (
        <window.SubirDocumentoModal
          inmuebleId={p._uid}
          onClose={() => setSubiendoDoc(false)}
          onSubido={trasSubirDoc}
        />
      )}
    </>
  );
};

window.InventoryView = InventoryView;
window.PropertyDetail = PropertyDetail;
window.PropCard = PropCard;
