// =========================================================================
// Shared UI primitives + Sidebar + TopBar
// =========================================================================

const Pill = ({ tone = "neutral", children, dot = true }) => (
  <span className={"pill " + tone}>
    {dot && tone !== "brand" && tone !== "red" && <span className="dot"/>}
    {children}
  </span>
);

// `fin` pinta la cifra según lo que representa: "fin-in" | "fin-out" |
// "fin-pend" | "fin-info" | "fin-zero" (ver financial.css). Sin `fin` el KPI
// se queda en el color de texto normal — que es lo correcto para los que no
// son dinero (nº de leads, días en pipeline…).
const KPI = ({ label, value, unit, delta, tone, sub, bar, accent, icon: I, fin }) => (
  <div className={"kpi" + (accent ? " accent" : "")}>
    <div className="kpi-eye">{I && <I/>}{label}</div>
    <div className={"kpi-val" + (fin ? " " + fin : "")}>{value}{unit && <span className="unit">{unit}</span>}</div>
    {delta && <div className={"kpi-delta " + (tone === "down" ? "down" : "up")}>{tone === "down" ? "↓" : "↑"} {delta}</div>}
    {sub && <div className="kpi-sub">{sub}</div>}
    {typeof bar === "number" && <div className="kpi-bar"><span style={{width: bar + "%"}}/></div>}
  </div>
);

// `cols` permite filas de más/menos de 4 KPIs sin romper el grid por defecto.
// A partir de 6 columnas las tarjetas bajan de ~150px y una cifra de 6 dígitos
// no cabe a 28px: `.kpi` tiene overflow:hidden, así que se recortaba en silencio.
// La clase `dense` reduce el cuerpo del número en vez de mutilarlo.
const KPIRow = ({ items, cols }) => (
  <div className={"kpi-row" + (cols >= 6 ? " dense" : "")} style={cols ? {gridTemplateColumns: `repeat(${cols}, 1fr)`} : undefined}>
    {items.map((k, i) => <KPI key={i} {...k}/>)}
  </div>
);

const PageHeader = ({ eyebrow, title, sub, actions }) => (
  <div className="page-h">
    <div>
      {eyebrow && <div className="eyebrow red" style={{marginBottom: 6}}>{eyebrow}</div>}
      <h1>{title}</h1>
      {sub && <div className="sub">{sub}</div>}
    </div>
    {actions && <div className="actions">{actions}</div>}
  </div>
);

const Card = ({ title, right, children, b = true, lg = false, style }) => (
  <div className={"card" + (lg ? " lg" : "")} style={style}>
    {title && (
      <div className="card-h">
        <h3>{title}</h3>
        {right && <div className="h-right">{right}</div>}
      </div>
    )}
    {b ? <div className="card-b">{children}</div> : children}
  </div>
);

// useGrouping:"always" fuerza el separador de millares también en 4 cifras
// (es-ES por defecto no agrupa números de 4 dígitos: "5685" -> "5.685").
const fmtEUR = (n) => (n == null ? "—" : n.toLocaleString("es-ES", { useGrouping: "always" }) + " €");
const fmtNum = (n) => n.toLocaleString("es-ES");

// ---- CIFRAS FINANCIERAS (ver financial.css) -----------------------------
// El color de un balance depende del SIGNO, y esa decisión se toma en una
// docena de sitios. Centralizada aquí para que "cero" no acabe pintado de
// verde en unos sitios y de rojo en otros: cero no es bueno ni malo.
const finBalCls = (n) => (n == null ? "" : n > 0 ? "fin-in" : n < 0 ? "fin-out" : "fin-zero");

// El estado manda sobre el signo: mientras algo está PENDIENTE lo relevante no
// es si suma o resta, es que aún no ha pasado por caja. Al cobrarse/pagarse
// adopta ya su color definitivo.
const finMovCls = (m) =>
  m.esOperacion ? "fin-info"
  : (m.estado === "pendiente" || m.estado === "vencido") ? "fin-pend"
  : m.tipo === "ingreso" ? "fin-in" : "fin-out";

// =========================================================================
// Sidebar
// =========================================================================

const Sidebar = ({ active, onNavigate, isAdmin }) => {
  const { Icons, DATA } = window;
  const pendTareas = (DATA?.TASKS || []).filter(t => !t.done).length;
  const Item = ({ id, icon: I, label, badge }) => (
    <div className={"sb-item " + (active === id ? "active" : "")} onClick={() => onNavigate(id)}>
      <I/>{label}{badge != null && <span className="sb-badge">{badge}</span>}
    </div>
  );
  return (
    <aside className="sb">
      <div className="sb-brand">
        <img src={(window.__resources && window.__resources.logoWhite) || "revin/assets/logo-wordmark-white.png"} alt="REVIN"/>
        <span className="sb-tag">v1.0</span>
      </div>
      <nav className="sb-nav">
        <div className="sb-group">{isAdmin ? "Vista global" : "Día a día"}</div>
        <Item id="dashboard" icon={Icons.Dash} label={isAdmin ? "Dashboard equipo" : "Hoy"}/>
        {/* El badge era un 4 escrito a mano: a un comercial nuevo le pintaba un
            aviso de cuatro cosas que no existen. El de Tareas se queda porque
            ese sí se cuenta de verdad (pendTareas). Sin dato, sin badge. */}
        <Item id="pipeline" icon={Icons.Pipeline} label="Pipeline"/>
        <Item id="tareas" icon={Icons.CheckSq} label="Tareas" badge={isAdmin ? null : (pendTareas || null)}/>
        <Item id="agenda" icon={Icons.Calendar} label="Agenda"/>

        <div className="sb-group">Cartera</div>
        <Item id="inmuebles" icon={Icons.Building} label="Inmuebles"/>
        <Item id="proyectos" icon={Icons.Grid} label="Proyectos"/>
        <Item id="clientes" icon={Icons.Users} label="Clientes / Leads"/>
        {/* Los proveedores son administrativos: un comercial no gestiona ninguno. */}
        {isAdmin && <Item id="proveedores" icon={Icons.Tool} label="Proveedores"/>}
        <Item id="mapa" icon={Icons.Map} label="Mapa"/>

        <div className="sb-group">{isAdmin ? "Equipo y finanzas" : "Cierre y finanzas"}</div>
        {isAdmin && <Item id="equipo" icon={Icons.Trophy} label="Comerciales"/>}
        {/* Contabilidad es la caja de la empresa. Un comercial no la ve en ningún
            momento — y menos aún un balance a 0 EUR porque RLS le oculta las
            filas: eso no sería un hueco, sería una cifra falsa. Lo suyo es
            "Mis comisiones", que sigue justo debajo. */}
        {isAdmin && <Item id="contabilidad" icon={Icons.Euro} label="Contabilidad"/>}
        <Item id="documentos" icon={Icons.Folder} label="Documentos"/>
        <Item id="facturas" icon={Icons.Receipt} label={isAdmin ? "Facturación global" : "Mis comisiones"}/>

        <div className="sb-group">Sistema</div>
        <Item id="ajustes" icon={Icons.Settings} label="Ajustes"/>
      </nav>
      <div className="sb-foot">
        <div className="sb-avatar">{(window.DATA?.USER?.initials) || (isAdmin ? "MR" : "EM")}</div>
        <div className="sb-foot-meta">
          <span className="sb-foot-name">{(window.DATA?.USER?.name) || (isAdmin ? "Marta Ruiz" : "Elena Molina")}</span>
          <span className="sb-foot-role">{(window.DATA?.USER?.role) || (isAdmin ? "Admin" : "Comercial")}</span>
        </div>
      </div>
    </aside>
  );
};

// =========================================================================
// Topbar
// =========================================================================

const TopBar = ({ crumbs, onSearch, onNotif, notifCount, viewName, isAdmin }) => {
  const { Icons } = window;
  return (
    <div className="tb">
      <div className="tb-left">
        <div className="tb-crumbs">
          {crumbs.map((c, i) => (
            <React.Fragment key={i}>
              {i > 0 && <span className="sep">/</span>}
              <span className={i === crumbs.length - 1 ? "cur" : ""}>{c}</span>
            </React.Fragment>
          ))}
        </div>
      </div>
      <div className="tb-right">
        <div className="tb-search" onClick={onSearch}>
          <Icons.Search/>
          <span className="ph">Buscar inmuebles, clientes, docs…</span>
          <span className="kbd">⌘K</span>
        </div>
        <button className="tb-icon-btn" title="Crear nuevo"><Icons.Plus/></button>
        <button className="tb-icon-btn" title="Notificaciones" onClick={onNotif}>
          <Icons.Bell/>
          {notifCount > 0 && <span className="badge">{notifCount}</span>}
        </button>
        <div className="tb-divider"/>
        <div className="tb-user">
          <div className="ava">{(window.DATA?.USER?.initials) || (isAdmin ? "MR" : "EM")}</div>
          <span className="name">{(window.DATA?.USER?.name?.split(" ")[0]) || (isAdmin ? "Marta" : "Elena")}</span>
          <Icons.ChevronDown size={12}/>
        </div>
      </div>
    </div>
  );
};

// ---------- MARCAS DE DATOS NO REALES (B0) ----------
// Dos formas, un solo criterio: `window.RevinMock.esMock()` (B0.a, en data.js).
//
//  · DemoDataBanner — de PÁGINA. Sin `bloque` significa «toda la pantalla», que
//    hoy solo ocurre sin sesión. Vive aquí, y no en Contabilidad.jsx, porque lo
//    montan tres módulos distintos y su sitio son los primitivos.
//  · DemoBlockMark  — de BLOQUE. Banda pegada al contenido que califica, no un
//    badge en la cabecera de la tarjeta: tres de los seis bloques marcados no
//    tienen cabecera, y un badge junto a «Modelo REVIN» se lee como etiqueta
//    de categoría. La banda no se puede leer como otra cosa.
//
// NO se suprimen entre sí. Sin sesión salen los dos y ambos dicen verdad: uno
// habla de la sesión, el otro del bloque. Suprimir uno exigiría un condicional
// cuyo modo de fallo es dejar de avisar — justo lo que B0 viene a evitar.
const DemoDataBanner = ({ bloque }) => {
  const { Icons } = window;
  if (!(window.RevinMock && window.RevinMock.esMock(bloque))) return null;
  return (
    <div className="demo-banner">
      <Icons.Alert/>
      <span><b>Datos de demostración</b> — inicia sesión («Conectar a Supabase») para ver los datos reales.</span>
    </div>
  );
};

const DemoBlockMark = ({ bloque, children }) => {
  if (!(window.RevinMock && window.RevinMock.esMock(bloque))) return null;
  return (
    <div className="demo-mark">
      <span className="demo-mark-tag">Ejemplo</span>
      <span>{children}</span>
    </div>
  );
};

// Para una sección que existe pero no es tuya. Dice QUÉ falta y A QUIÉN
// pedírselo — un panel en blanco se lee como una avería y acaba en una llamada
// a Carlos preguntando si el CRM se ha roto.
const SinPermiso = ({ que }) => {
  const { Icons } = window;
  return (
    <div className="empty" style={{minHeight: "60vh", justifyContent: "center"}}>
      <div className="icon-wrap"><Icons.Alert/></div>
      <div style={{fontSize: 16, fontWeight: 700, marginBottom: 8}}>Esta sección no es para tu perfil</div>
      <div style={{fontSize: 13, color: "var(--fg-3)", maxWidth: 420, lineHeight: 1.5}}>
        {que ? "El acceso a " + que + " está reservado a administración." : "Acceso reservado a administración."}
        {" "}Si necesitas algo de aquí, pídeselo a Carlos.
      </div>
    </div>
  );
};

window.SinPermiso = SinPermiso;
window.Pill = Pill;
window.KPI = KPI;
window.KPIRow = KPIRow;
window.PageHeader = PageHeader;
window.Card = Card;
window.fmtEUR = fmtEUR;
window.fmtNum = fmtNum;
window.finBalCls = finBalCls;
window.finMovCls = finMovCls;
window.Sidebar = Sidebar;
window.TopBar = TopBar;
window.DemoDataBanner = DemoDataBanner;
window.DemoBlockMark = DemoBlockMark;
