/* =====================================================================
   Trascend · Portal de Cliente — App React
   ===================================================================== */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- constantes de dominio ---------------------------------------- */
const CH_COLOR   = { whatsapp:'#1FA855', email:'#2F5FC4' };
const CH_LABEL   = { whatsapp:'WA', email:'✉' };

/* ---- conexiones de canales (por cliente, centralizadas en el portal) ---- */
const CONN_STATUS = { connected:{label:'Conectado',cls:'pb-ok'}, pending:{label:'Sin conectar',cls:'pb-warn'}, off:{label:'Desactivado',cls:'pb-dim'} };
const CONN_CATALOG = [
  { channel:'whatsapp',  name:'WhatsApp Business',           color:'#1FA855', short:'WA', desc:'AGE atiende y responde tus chats de WhatsApp.',   fields:[{k:'account_ref',label:'Número / Phone Number ID',ph:'+598 99 000 000'},{k:'token',label:'Token de acceso',secret:true}] },
  { channel:'instagram', name:'Instagram — Mensajes directos', color:'#C13584', short:'IG', desc:'Responder los DMs de tu cuenta de Instagram.',          fields:[{k:'account_ref',label:'Usuario / ID de cuenta',ph:'@tucuenta'},{k:'token',label:'Token (autorización Meta)',secret:true}] },
  { channel:'facebook',  name:'Facebook Messenger',          color:'#1877F2', short:'FB', desc:'Atender el Messenger de tu página de Facebook.',       fields:[{k:'account_ref',label:'Page ID',ph:'ID de la página'},{k:'token',label:'Token de página',secret:true}] },
  { channel:'email',     name:'Email',                       color:'#2F5FC4', short:'✉', desc:'Responder las consultas que llegan por correo.',        fields:[{k:'account_ref',label:'Casilla de correo',ph:'ventas@tuempresa.com'},{k:'token',label:'Contraseña de app / SMTP',secret:true}] },
];
/* Lo que Trascend vende hoy. Si algo no está en el sitio, no va acá. */
const CROSS_SELL = [
  { title:'Otra automatización',  desc:'Sacamos otra tarea repetitiva de las manos de tu equipo. Una por vez, con precio cerrado.' },
  { title:'Una función de IA',    desc:'Clasificar consultas, resumir mensajes o extraer datos de documentos, sobre lo que ya corre.' },
  { title:'Revisión QA',          desc:'Probamos tu web o sistema de punta a punta y te dejamos los errores ordenados por impacto.' },
  { title:'AGE · atención con IA',desc:'Responde por WhatsApp, web y email a cualquier hora, y deriva a una persona cuando no sabe.' },
];

/* Etapas vistas desde el cliente: lo que Trascend llama pipeline, para él es
   el avance de su proyecto. Mismos estados, nombres que le sirven a él. */
const STAGE_LABEL = { prospecto:'Por arrancar', contactado:'En relevamiento', propuesta:'Propuesta enviada', negociacion:'En revisión', ganado:'Entregado', perdido:'No avanzó' };
const STAGE_CLS   = { prospecto:'pb-dim', contactado:'pb-info', propuesta:'pb-violet', negociacion:'pb-warn', ganado:'pb-ok', perdido:'pb-danger' };
const STAGE_ORD   = ['prospecto','contactado','propuesta','negociacion','ganado','perdido'];

const REQ_TYPE_LABEL   = { consulta:'Consulta', aprobacion:'Aprobación', cambio:'Cambio', material:'Accesos' };
const REQ_TYPE_CLS     = { consulta:'pb-info', aprobacion:'pb-violet', cambio:'pb-warn', material:'pb-dim' };
const REQ_STATUS_LABEL = { nueva:'Nueva', en_proceso:'En proceso', resuelta:'Resuelta' };
const REQ_STATUS_CLS   = { nueva:'pb-warn', en_proceso:'pb-info', resuelta:'pb-ok' };

const INV_STATUS_LABEL = { pendiente:'Pendiente', pagada:'Pagada', vencida:'Vencida' };
const INV_STATUS_CLS   = { pendiente:'pb-warn', pagada:'pb-ok', vencida:'pb-danger' };
const QUOTE_STATUS_LABEL = { borrador:'Borrador', enviado:'Enviado', aceptado:'Aceptado', rechazado:'Rechazado' };
const QUOTE_STATUS_CLS   = { borrador:'pb-dim', enviado:'pb-info', aceptado:'pb-ok', rechazado:'pb-danger' };

const CUR = { USD:'US$', ARS:'AR$', UYU:'$U' };
const fmtMoney = (v,c) => `${CUR[c]||c} ${Number(v||0).toLocaleString('es-UY',{maximumFractionDigits:0})}`;
const fmtDate  = (iso) => { if (!iso) return '—'; const d = new Date(iso.length===10?iso+'T12:00:00':iso); return d.toLocaleDateString('es-UY',{day:'2-digit',month:'short'}); };
const fmtDT    = (iso) => { if (!iso) return '—'; const d = new Date(iso); return d.toLocaleDateString('es-UY',{day:'2-digit',month:'short'})+' · '+d.toLocaleTimeString('es-UY',{hour:'2-digit',minute:'2-digit'}); };
const inits    = (n)   => String(n||'?').split(/\s+/).map(w=>w[0]).slice(0,2).join('').toUpperCase();

/* ---- iconos --------------------------------------------------------- */
const IB = (p) => <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...p}>{p.children}</svg>;
const PI = {
  home:    p=><IB {...p}><path d="M3 8.5 10 3l7 5.5V17a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V8.5Z"/><path d="M8 18v-6h4v6"/></IB>,
  deals:   p=><IB {...p}><path d="M3 5h14M5.5 10h9M8 15h4"/></IB>,
  invoice: p=><IB {...p}><rect x="4" y="3" width="12" height="14" rx="2"/><path d="M7 7h6M7 10h6M7 13h3.5"/></IB>,
  request: p=><IB {...p}><path d="M3 18l2-6h10l2 6"/><rect x="6" y="3" width="8" height="9" rx="2"/></IB>,
  message: p=><IB {...p}><path d="M3 11l2.5-6.5h9L17 11"/><path d="M3 11v4a1.5 1.5 0 0 0 1.5 1.5h11A1.5 1.5 0 0 0 17 15v-4"/><path d="M3 11h4l1 2h4l1-2h4"/></IB>,
  logout:  p=><IB {...p}><path d="M8 17H4.5A1.5 1.5 0 0 1 3 15.5v-11A1.5 1.5 0 0 1 4.5 3H8M13 13.5 16.5 10 13 6.5M16.5 10H7.5"/></IB>,
  arrow:   p=><IB {...p}><path d="M4 10h11.5M11 5.5 15.5 10 11 14.5"/></IB>,
  plus:    p=><IB {...p}><path d="M10 4.5v11M4.5 10h11"/></IB>,
  check:   p=><IB {...p}><path d="m4 10.5 4 4 8-9"/></IB>,
  dl:      p=><IB {...p}><path d="M10 3v9M6.4 8.6 10 12.2l3.6-3.6M5 16h10"/></IB>,
  plug:    p=><IB {...p}><path d="M7 3v4M13 3v4M5 7h10v2a5 5 0 0 1-10 0V7ZM10 14v3"/></IB>,
  spark:   p=><IB {...p}><path d="M10 3l1.7 4.3L16 9l-4.3 1.7L10 15l-1.7-4.3L4 9l4.3-1.7L10 3Z"/></IB>,
  lock:    p=><IB {...p}><rect x="4.5" y="9" width="11" height="7" rx="1.5"/><path d="M7 9V6.5a3 3 0 0 1 6 0V9"/></IB>,
};

/* ---- primitivas ----------------------------------------------------- */
function useToast() {
  const [msg, setMsg] = useState(null);
  const t = useRef(null);
  const show = useCallback(m => { setMsg(m); clearTimeout(t.current); t.current = setTimeout(()=>setMsg(null),2700); }, []);
  return [show, msg ? <div className="p-toast">{msg}</div> : null];
}

function PBadge({ cls, label }) { return <span className={"pbadge "+(cls||'')}>{label}</span>; }
function PAvatar({ name, small }) { return <div className={"p-avatar"+(small?' p-avatar-sm':'')}>{inits(name)}</div>; }

/* =====================================================================
   LOGIN
   ===================================================================== */
function LoginScreen({ onLogin }) {
  const [email, setEmail] = useState('');
  const [pass,  setPass]  = useState('');
  const [err,   setErr]   = useState(null);
  const [busy,  setBusy]  = useState(false);

  function submit(e) {
    e.preventDefault(); setErr(null); setBusy(true);
    PortalAuth.login(email, pass).then((r) => {
      setBusy(false);
      if (r && r.ok) { onLogin(r.portalUser); return; }
      var msg = (r && r.error) || '';
      var isNet = /conect|network|servidor|conexión|http\s*5\d\d|\b50\d\b|502|503|504/i.test(msg);
      setErr(isNet ? 'No se pudo conectar con el servidor. Reintentá en unos segundos.' : 'Dato ingresado incorrecto, porfavor revise');
    }).catch(() => {
      setBusy(false);
      setErr('No se pudo conectar con el servidor. Reintentá en unos segundos.');
    });
  }

  return (
    <div className="p-login-screen">
      <div className="p-login-card">
        <div className="p-login-logo">
          <img src="../assets/logo-trascend.png" alt="" />
          <span><b>Trascend</b><em>Portal de cliente</em></span>
        </div>
        <h2>Accedé a tu portal</h2>
        <p>Seguí tu operación, mirá tus facturas y envianos lo que necesites.</p>
        <form className="p-login-form" onSubmit={submit}>
          {err && <div className="p-login-error">{err}</div>}
          <div className="p-login-field">
            <label>Email</label>
            <input className="p-login-inp" type="email" required autoComplete="username"
              value={email} onChange={e=>setEmail(e.target.value)} placeholder="tu@empresa.com" />
          </div>
          <div className="p-login-field">
            <label>Contraseña</label>
            <input className="p-login-inp" type="password" required autoComplete="current-password"
              value={pass} onChange={e=>setPass(e.target.value)} placeholder="••••••••" />
          </div>
          <button className="p-login-btn" type="submit" disabled={busy}>
            {busy ? 'Verificando…' : 'Ingresar'}{!busy && <PI.arrow style={{width:16,height:16}} />}
          </button>
        </form>
      </div>
    </div>
  );
}

/* =====================================================================
   SHELL
   ===================================================================== */

/* =====================================================================
   Mi operación · lo que el cliente puede supervisar sin preguntar:
   qué automatizaciones tiene corriendo, cuántas horas le devuelven y
   en qué estado está la verificación de su sistema.
   ===================================================================== */
const OP_FSTATUS = { produccion:{l:'Funcionando',c:'p-ok'}, pruebas:{l:'En pruebas',c:'p-info'}, pausado:{l:'Pausado',c:'p-warn'}, diseno:{l:'En preparación',c:'p-dim'}, retirado:{l:'Retirado',c:'p-dim'} };
const OP_SEV = { critica:{l:'Crítica',c:'p-danger'}, alta:{l:'Alta',c:'p-warn'}, media:{l:'Media',c:'p-info'}, baja:{l:'Baja',c:'p-dim'} };
const OP_FIND = { abierto:{l:'Lo estamos viendo',c:'p-warn'}, cliente:{l:'Esperando tu equipo',c:'p-info'}, reprueba:{l:'A reprobar',c:'p-info'}, cerrado:{l:'Resuelto',c:'p-ok'} };

function OperacionPage({ user, setRoute }) {
  const flows    = PortalData.getFlows(user.clientId);
  const runs     = PortalData.getFlowRuns(user.clientId);
  const suites   = PortalData.getQaSuites(user.clientId);
  const qaRuns   = PortalData.getQaRuns(user.clientId);
  const findings = PortalData.getQaFindings(user.clientId);

  const live     = flows.filter(f => f.status === 'produccion');
  const savedH   = live.reduce((a, f) => a + (Number(f.saved_h_month) || 0), 0);
  const okRuns   = runs.filter(r => r.status !== 'error').length;
  const okRate   = runs.length ? Math.round((okRuns / runs.length) * 100) : 100;
  const openF    = findings.filter(f => f.status !== 'cerrado');
  const critical = openF.filter(f => f.severity === 'critica').length;

  const fmt = (d) => { try { return new Date(d).toLocaleString('es-UY', { day:'2-digit', month:'short', hour:'2-digit', minute:'2-digit' }); } catch(e) { return String(d).slice(0,16).replace('T',' '); } };

  if (!flows.length && !suites.length) {
    return (
      <div className="p-card p-empty">
        <PI.spark />
        <h3>Todavía no hay nada publicado acá</h3>
        <p>Cuando pongamos en marcha tu primera automatización o verificación, vas a poder ver acá su estado en tiempo real, sin tener que preguntarnos.</p>
        <button className="p-btn p-btn-primary" onClick={() => setRoute('peticiones')}>Pedir algo al equipo</button>
      </div>
    );
  }

  return (
    <div className="p-stack">
      <div className="p-kpis">
        <div className="p-card p-kpi"><span className="p-kpi-label">Horas que te devolvemos</span><div className="p-kpi-value">{savedH} h</div><div className="p-kpi-foot">por mes, estimadas sobre tu proceso</div></div>
        <div className="p-card p-kpi"><span className="p-kpi-label">Automatizaciones activas</span><div className="p-kpi-value">{live.length}</div><div className="p-kpi-foot">de {flows.length} configuradas</div></div>
        <div className="p-card p-kpi"><span className="p-kpi-label">Ejecuciones sin error</span><div className="p-kpi-value">{okRate}%</div><div className="p-kpi-foot">sobre las últimas {runs.length}</div></div>
        <div className="p-card p-kpi"><span className="p-kpi-label">Cosas por resolver</span><div className="p-kpi-value">{openF.length}</div><div className="p-kpi-foot">{critical ? critical + ' crítica(s)' : 'ninguna urgente'}</div></div>
      </div>

      {!!flows.length && <div className="p-card">
        <div className="p-card-head"><h3>Tus automatizaciones</h3><span className="p-dim">Qué está corriendo ahora mismo</span></div>
        <div className="p-list">
          {flows.map(f => {
            const rs = runs.filter(r => r.flow_id === f.id);
            const last = rs[0];
            const st = OP_FSTATUS[f.status] || OP_FSTATUS.diseno;
            return (
              <div className="p-list-row" key={f.id}>
                <div className="p-list-main">
                  <b>{f.name}</b>
                  <span className="p-dim">{last ? 'Última vez: ' + fmt(last.ran_at) : 'Sin ejecuciones todavía'}</span>
                </div>
                <div className="p-list-side">
                  <span className="p-chip p-ok">{f.saved_h_month} h/mes</span>
                  <span className={'p-chip ' + st.c}>{st.l}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>}

      {!!suites.length && <div className="p-card">
        <div className="p-card-head"><h3>Verificación de tu sistema</h3><span className="p-dim">Lo probamos por vos, con esta frecuencia</span></div>
        <div className="p-list">
          {suites.map(s => {
            const last = qaRuns.filter(r => r.suite_id === s.id)[0];
            const op = openF.filter(f => f.suite_id === s.id).length;
            return (
              <div className="p-list-row" key={s.id}>
                <div className="p-list-main">
                  <b>{s.name}</b>
                  <span className="p-dim">{last ? 'Última verificación: ' + fmt(last.started_at) + ' · ' + last.passed + ' de ' + (last.passed + last.failed) + ' correctos' : 'Todavía sin verificar'}</span>
                </div>
                <div className="p-list-side">
                  <span className={'p-chip ' + (op ? 'p-warn' : 'p-ok')}>{op ? op + ' pendiente(s)' : 'Todo en orden'}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>}

      {!!openF.length && <div className="p-card">
        <div className="p-card-head"><h3>Qué encontramos</h3><span className="p-dim">Ordenado por lo que más te afecta</span></div>
        <div className="p-list">
          {openF.slice().sort((a,b) => (OP_SEV[b.severity]? Object.keys(OP_SEV).indexOf(a.severity) - Object.keys(OP_SEV).indexOf(b.severity) : 0)).map(f => {
            const sv = OP_SEV[f.severity] || OP_SEV.baja;
            const st = OP_FIND[f.status] || OP_FIND.abierto;
            return (
              <div className="p-list-row" key={f.id}>
                <div className="p-list-main">
                  <b>{f.title}</b>
                  {f.impact && <span className="p-dim">{f.impact}</span>}
                </div>
                <div className="p-list-side">
                  <span className={'p-chip ' + sv.c}>{sv.l}</span>
                  <span className={'p-chip ' + st.c}>{st.l}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>}

      {!!runs.length && <div className="p-card">
        <div className="p-card-head"><h3>Actividad reciente</h3><span className="p-dim">Cada vez que una automatización trabajó por vos</span></div>
        <div className="p-list">
          {runs.slice(0, 12).map(r => {
            const fl = flows.find(f => f.id === r.flow_id) || {};
            const bad = r.status === 'error';
            return (
              <div className="p-list-row" key={r.id}>
                <div className="p-list-main">
                  <b>{fl.name || '—'}</b>
                  <span className="p-dim">{fmt(r.ran_at)}{r.items ? ' · ' + r.items + ' ítem(s) procesado(s)' : ''}{bad ? ' · ' + r.error : ''}</span>
                </div>
                <div className="p-list-side">
                  <span className={'p-chip ' + (bad ? 'p-danger' : 'p-ok')}>{bad ? 'Con error' : 'OK'}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>}
    </div>
  );
}

const TITLES = { inicio:'Inicio', operacion:'Mi operación', proyectos:'Mis proyectos', facturas:'Facturas', peticiones:'Peticiones', mensajes:'Mensajes', conexiones:'Canales & conexiones' };
const NAV = [
  { key:'inicio',     label:'Inicio',        Icon:PI.home    },
  { key:'operacion',  label:'Mi operación',  Icon:PI.spark   },
  { key:'proyectos',  label:'Mis proyectos', Icon:PI.deals   },
  { key:'conexiones', label:'Conexiones',    Icon:PI.plug    },
  { key:'facturas',   label:'Facturas',      Icon:PI.invoice },
  { key:'peticiones', label:'Peticiones',    Icon:PI.request },
  { key:'mensajes',   label:'Mensajes',      Icon:PI.message },
];

function Shell({ user, route, setRoute, onLogout, pendingReq, children }) {
  return (
    <div className="p-shell">
      <aside className="p-sidebar">
        <div className="p-sb-logo">
          <img src="../assets/logo-trascend.png" alt="" />
          <span><b>Trascend</b><em>Operaciones digitales</em></span>
        </div>
        <div className="p-sb-client">
          <div className="p-sb-client-label">Tu cuenta</div>
          <div className="p-sb-client-name">{user.client.name}</div>
        </div>
        <nav className="p-sb-nav">
          {NAV.map(({ key, label, Icon }) => (
            <button key={key} className={"p-sb-item"+(route===key?' is-active':'')} onClick={()=>setRoute(key)}>
              <Icon /><span>{label}</span>
              {key==='peticiones' && pendingReq > 0 && <span className="p-sb-count">{pendingReq}</span>}
            </button>
          ))}
        </nav>
        <div className="p-sb-footer">
          <div className="p-sb-user">
            <PAvatar name={user.contactName} small />
            <span><b>{user.contactName}</b><span>{user.client.name}</span></span>
          </div>
          <button className="p-sb-item" onClick={onLogout}><PI.logout /><span>Cerrar sesión</span></button>
        </div>
      </aside>
      <div className="p-main">
        <header className="p-topbar">
          <h1>{TITLES[route]||route}</h1>
          <div className="p-topbar-space" />
          <span style={{fontSize:'0.72rem',color:'var(--text-dim)'}}>Portal del cliente · demo</span>
        </header>
        <div className="p-content">{children}</div>
      </div>
    </div>
  );
}

/* =====================================================================
   HOME
   ===================================================================== */
/* Guía de bienvenida · se muestra hasta que el cliente la cierra */
const P_GUIDE_KEY = 'trascend_portal_guide_v1';
const P_SEEN_KEY = 'trascend_portal_seen_v1';

/* Onboarding del cliente · no es un texto para leer: son cuatro pasos que se
   marcan solos con el estado real de su cuenta. Cuando los cuatro están
   hechos, la tarjeta se apaga y no vuelve. */
function PortalGuide({ user, setRoute }) {
  const cid = user.clientId;
  const kSeen = P_SEEN_KEY + ':' + cid;
  const kOff  = P_GUIDE_KEY + ':' + cid;
  const [dismissed, setDismissed] = React.useState(() => { try { return localStorage.getItem(kOff) === 'off'; } catch (e) { return false; } });
  const [seen, setSeen] = React.useState(() => { try { return JSON.parse(localStorage.getItem(kSeen) || '[]'); } catch (e) { return []; } });

  const conns    = PortalData.getConnections(cid) || [];
  const requests = PortalData.getRequests(cid) || [];
  const flows    = PortalData.getFlows(cid) || [];
  const runs     = PortalData.getFlowRuns(cid) || [];

  const mark = (key, route) => {
    const next = seen.includes(key) ? seen : seen.concat(key);
    setSeen(next);
    try { localStorage.setItem(kSeen, JSON.stringify(next)); } catch (e) {}
    setRoute(route);
  };

  const steps = [
    { k: 'conexiones', r: 'conexiones', t: 'Conectá tus canales',
      d: 'Vinculás tu WhatsApp y tus redes para que trabajemos sobre tus cuentas, no sobre las nuestras.',
      done: conns.some((c) => c.status === 'connected'),
      hint: 'Todo queda a tu nombre y podés revocarlo cuando quieras.' },
    { k: 'operacion', r: 'operacion', t: 'Mirá qué está corriendo',
      d: 'En Mi operación ves las automatizaciones activas y las horas que te devolvieron este mes.',
      done: seen.includes('operacion'),
      hint: flows.length ? flows.length + ' automatización(es) en tu cuenta' : 'Todavía no hay nada instalado' },
    { k: 'peticiones', r: 'peticiones', t: 'Dejá tu primer pedido',
      d: 'Lo que necesites queda registrado con su estado. Sin cadenas de mails ni recordarle a nadie.',
      done: requests.length > 0,
      hint: requests.length ? requests.length + ' pedido(s) registrados' : 'Probalo con cualquier cosa: se responde igual' },
    { k: 'proyectos', r: 'proyectos', t: 'Seguí tu proyecto',
      d: 'El avance de lo que nos encargaste, con su alcance acordado y la fecha estimada de entrega.',
      done: seen.includes('proyectos'),
      hint: runs.length ? runs.length + ' ejecución(es) registradas' : 'Sin ejecuciones todavía' },
  ];

  const doneN = steps.filter((s) => s.done).length;
  const complete = doneN === steps.length;
  if (dismissed) return null;

  const close = () => { setDismissed(true); try { localStorage.setItem(kOff, 'off'); } catch (e) {} };

  return (
    <div className={'p-card p-guide' + (complete ? ' p-guide-done' : '')}>
      <div className="p-card-head">
        <div>
          <b>{complete ? 'Ya está todo listo' : 'Poner tu cuenta en marcha'}</b>
          <div className="p-dim">
            {complete
              ? 'Completaste los cuatro pasos. Podés cerrar esto: tu portal queda igual.'
              : 'Cuatro pasos. Se marcan solos a medida que los hacés.'}
          </div>
        </div>
        <div className="p-guide-meter">
          <span className="p-guide-count">{doneN}<i>/{steps.length}</i></span>
          <span className="p-guide-bar"><i style={{ width: (doneN / steps.length * 100) + '%' }}></i></span>
        </div>
        <button className="p-btn p-btn-ghost" onClick={close}>{complete ? 'Cerrar' : 'Ocultar'}</button>
      </div>
      <div className="p-guide-grid">
        {steps.map((it, i) => (
          <button key={it.k} className={'p-guide-step' + (it.done ? ' is-done' : '')} onClick={() => mark(it.k, it.r)}>
            <span className="p-guide-n">{it.done ? '✓' : i + 1}</span>
            <b>{it.t}</b>
            <span className="p-dim">{it.d}</span>
            <span className="p-guide-hint">{it.hint}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

function HomePage({ user, setRoute }) {
  const cid = user.clientId;
  const deals    = PortalData.getDeals(cid);
  const invoices = PortalData.getInvoices(cid);
  const requests = PortalData.getRequests(cid);
  const flows    = PortalData.getFlows(cid) || [];
  const runs     = PortalData.getFlowRuns(cid) || [];

  const activeDeals   = deals.filter(d=>!['ganado','perdido'].includes(d.stage)).length;
  const liveFlows     = flows.filter(f=>f.status==='produccion').length;
  const savedH        = flows.reduce((a,f)=>a+Number(f.hours_saved_month||0),0);
  const pendInvoices  = invoices.filter(i=>['pendiente','vencida'].includes(i.status)).length;
  const openRequests  = requests.filter(r=>r.status!=='resuelta').length;

  /* Lo último que hizo su operación: la prueba de que corre sin que él mire. */
  const lastRuns = runs.slice().sort((a,b)=>String(b.ran_at).localeCompare(String(a.ran_at))).slice(0,4);
  const flowName = (id) => (flows.find(f=>f.id===id)||{}).name || 'Automatización';
  const recentReqs  = requests.slice(0,3);

  return (
    <div className="p-stack">
      <div className="p-welcome">
        <h2>Hola, {user.contactName.split(' ')[0]} 👋</h2>
        <p>Resumen del trabajo que estamos haciendo para <b>{user.client.name}</b>.</p>
      </div>

      <PortalGuide user={user} setRoute={setRoute} />

      <div className="p-grid-4">
        <div className="p-stat" onClick={()=>setRoute('operacion')}>
          <div className="p-stat-label">Horas devueltas por mes</div>
          <div className="p-stat-value">{savedH}</div>
        </div>
        <div className="p-stat" onClick={()=>setRoute('operacion')}>
          <div className="p-stat-label">Automatizaciones corriendo</div>
          <div className="p-stat-value">{liveFlows}</div>
        </div>
        <div className={"p-stat"+(pendInvoices>0?' is-danger':'')} onClick={()=>setRoute('facturas')}>
          <div className="p-stat-label">Facturas pendientes</div>
          <div className="p-stat-value">{pendInvoices}</div>
        </div>
        <div className="p-stat" onClick={()=>setRoute('peticiones')}>
          <div className="p-stat-label">Solicitudes abiertas</div>
          <div className="p-stat-value">{openRequests}</div>
        </div>
      </div>

      <div className="p-grid-2">
        <div className="p-card">
          <div className="p-card-head">
            <h3>Lo último que corrió</h3><div className="sp"/>
            <button className="p-btn p-btn-ghost p-btn-sm" onClick={()=>setRoute('operacion')}>Ver todo</button>
          </div>
          <div className="p-card-pad">
            {lastRuns.length===0
              ? <div className="p-empty"><b>Todavía no hay ejecuciones</b>Cuando tu primera automatización entre en producción, aparecen acá.</div>
              : lastRuns.map(r=>(
                  <div className="p-post" key={r.id}>
                    <div className="p-net-dot" style={{background:r.status==='ok'?'#1FA855':'#C4304A'}}>{r.status==='ok'?'✓':'!'}</div>
                    <div style={{flex:1}}>
                      <div className="p-post-title">{flowName(r.flow_id)}</div>
                      <div className="p-post-copy">{r.status==='ok' ? (Number(r.items||0)+' elemento(s) procesados sin error') : (r.error || 'Terminó con error, lo estamos viendo')}</div>
                      <div className="p-post-meta"><span>{fmtDT(r.ran_at)}</span></div>
                    </div>
                  </div>
                ))
            }
          </div>
        </div>

        <div className="p-card">
          <div className="p-card-head">
            <h3>Mis solicitudes</h3><div className="sp"/>
            <button className="p-btn p-btn-ghost p-btn-sm" onClick={()=>setRoute('peticiones')}>Ver todo</button>
          </div>
          <div className="p-card-pad">
            {recentReqs.length===0
              ? <div className="p-empty"><b>Sin solicitudes aún</b></div>
              : recentReqs.map(r=>(
                  <div className="p-req" key={r.id}>
                    <div className="p-req-row">
                      <PBadge cls={REQ_STATUS_CLS[r.status]} label={REQ_STATUS_LABEL[r.status]} />
                      <PBadge cls={REQ_TYPE_CLS[r.type]} label={REQ_TYPE_LABEL[r.type]} />
                      <span style={{fontSize:'0.72rem',color:'var(--text-dim)',marginLeft:'auto'}}>{fmtDate(r.created_at)}</span>
                    </div>
                    <div className="p-req-title">{r.title}</div>
                    {r.team_note && <div className="p-req-note"><b>Trascend:</b> {r.team_note}</div>}
                  </div>
                ))
            }
          </div>
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   PROYECTOS — el avance de lo que nos encargó
   ===================================================================== */
function ProyectosPage({ user }) {
  const deals = PortalData.getDeals(user.clientId);
  return (
    <div className="p-card">
      <div className="p-card-head"><h3>Tus proyectos</h3><div className="sp"/><span style={{fontSize:'0.76rem',color:'var(--text-dim)'}}>Alcance y precio se acuerdan por escrito antes de arrancar</span></div>
      <div className="p-card-pad">
        {deals.length===0 ? <div className="p-empty"><b>Sin proyectos registrados</b>Cuando arranquemos el primero, su avance aparece acá.</div> : (
          <table className="p-tbl">
            <thead><tr><th>Proyecto</th><th>Valor</th><th>Avance</th><th>Estado</th><th>Entrega est.</th></tr></thead>
            <tbody>
              {deals.map(d=>{
                const idx = STAGE_ORD.indexOf(d.stage);
                const pct = d.stage==='perdido' ? 0 : d.stage==='ganado' ? 100 : Math.round(((idx+1)/5)*100);
                return (
                  <tr key={d.id}>
                    <td><b style={{fontSize:'0.86rem'}}>{d.title}</b></td>
                    <td className="mono" style={{fontSize:'0.8rem'}}>{fmtMoney(d.value,d.currency)}</td>
                    <td style={{minWidth:130}}>
                      {!['ganado','perdido'].includes(d.stage) && <div className="p-prog"><div className="p-prog-fill" style={{width:pct+'%'}}></div></div>}
                      <div className="p-stage-label">{STAGE_LABEL[d.stage]}</div>
                    </td>
                    <td><PBadge cls={STAGE_CLS[d.stage]} label={STAGE_LABEL[d.stage]} /></td>
                    <td style={{fontSize:'0.79rem',color:'var(--text-dim)'}}>{fmtDate(d.expected_close)}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

/* =====================================================================
   FACTURAS Y PRESUPUESTOS — lo que se le cobró y lo que se le propuso
   ===================================================================== */
function FacturasPage({ user }) {
  const invoices = PortalData.getInvoices(user.clientId);
  const quotes   = PortalData.getQuotes(user.clientId);
  const pend = invoices.filter(i=>['pendiente','vencida'].includes(i.status));

  return (
    <div className="p-stack">
      <div className="p-card">
        <div className="p-card-head">
          <h3>Facturas</h3><div className="sp"/>
          {pend.length > 0 && <PBadge cls="pb-warn" label={pend.length+' pendiente'+(pend.length===1?'':'s')} />}
        </div>
        <div className="p-card-pad">
          {invoices.length===0 ? <div className="p-empty"><b>Sin facturas todavía</b>Cuando emitamos la primera, aparece acá con su estado.</div> : (
            <table className="p-tbl">
              <thead><tr><th>Número</th><th>Concepto</th><th>Emitida</th><th>Vence</th><th>Importe</th><th>Estado</th></tr></thead>
              <tbody>
                {invoices.slice().sort((a,b)=>String(b.issued_at||'').localeCompare(String(a.issued_at||''))).map(i=>(
                  <tr key={i.id}>
                    <td className="mono" style={{fontSize:'0.79rem'}}>{i.number || '—'}</td>
                    <td><b style={{fontSize:'0.85rem'}}>{i.concept}</b></td>
                    <td style={{fontSize:'0.79rem',color:'var(--text-dim)'}}>{fmtDate(i.issued_at)}</td>
                    <td style={{fontSize:'0.79rem',color:'var(--text-dim)'}}>{fmtDate(i.due_at)}</td>
                    <td className="mono" style={{fontSize:'0.82rem'}}>{fmtMoney(i.amount,i.currency)}</td>
                    <td><PBadge cls={INV_STATUS_CLS[i.status]} label={INV_STATUS_LABEL[i.status]} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>

      <div className="p-card">
        <div className="p-card-head"><h3>Presupuestos</h3><div className="sp"/><span style={{fontSize:'0.76rem',color:'var(--text-dim)'}}>Alcance y precio cerrados antes de arrancar</span></div>
        <div className="p-card-pad">
          {quotes.length===0 ? <div className="p-empty"><b>Sin presupuestos</b>Los que te enviemos quedan acá, con su estado.</div> : (
            <table className="p-tbl">
              <thead><tr><th>Número</th><th>Concepto</th><th>Válido hasta</th><th>Importe</th><th>Estado</th></tr></thead>
              <tbody>
                {quotes.slice().sort((a,b)=>String(b.valid_until||'').localeCompare(String(a.valid_until||''))).map(q=>(
                  <tr key={q.id}>
                    <td className="mono" style={{fontSize:'0.79rem'}}>{q.number || '—'}</td>
                    <td><b style={{fontSize:'0.85rem'}}>{q.concept}</b></td>
                    <td style={{fontSize:'0.79rem',color:'var(--text-dim)'}}>{fmtDate(q.valid_until)}</td>
                    <td className="mono" style={{fontSize:'0.82rem'}}>{fmtMoney(q.amount,q.currency)}</td>
                    <td><PBadge cls={QUOTE_STATUS_CLS[q.status]} label={QUOTE_STATUS_LABEL[q.status]} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   PETICIONES — lo que necesita, registrado y con estado
   ===================================================================== */
function PeticionesPage({ user }) {
  const [reqs, setReqs] = useState(()=>PortalData.getRequests(user.clientId));
  const [sf, setSF]     = useState(false);
  const [toast, toastNode] = useToast();
  const [f, setF] = useState({ title:'', type:'consulta', description:'' });
  const set = (k) => (e) => setF({ ...f, [k]: e.target.value });
  const reload = ()=>setReqs(PortalData.getRequests(user.clientId));

  async function send() {
    if (f.title.trim().length < 3) { toast('Ponele un título para saber de qué se trata'); return; }
    await PortalData.createRequest(user.clientId, user.contactId, f);
    setF({ title:'', type:'consulta', description:'' });
    setSF(false); reload(); toast('Pedido registrado — te respondemos por acá');
  }

  return (
    <div className="p-stack">
      <div className="p-card">
        <div className="p-card-head" style={{alignItems:'flex-start'}}>
          <div>
            <h2 style={{fontFamily:'var(--font-display)',fontSize:'1.1rem',fontWeight:800,letterSpacing:'-0.02em'}}>Mis solicitudes</h2>
            <p style={{fontSize:'0.81rem',color:'var(--text-dim)',marginTop:3}}>Lo que necesites queda registrado con su estado. Sin cadenas de mails ni recordarle a nadie.</p>
          </div>
          <div className="sp"/>
          <button className="p-btn p-btn-primary" onClick={()=>setSF(v=>!v)}>
            {sf ? 'Cancelar' : 'Nuevo pedido'}
          </button>
        </div>

        {sf && (
          <div className="p-card-pad" style={{borderBottom:'1px solid var(--line-soft)',display:'flex',flexDirection:'column',gap:12}}>
            <label style={{display:'flex',flexDirection:'column',gap:5}}>
              <span style={{fontSize:'0.76rem',color:'var(--text-dim)',fontWeight:600}}>¿Qué necesitás?</span>
              <input className="p-input" value={f.title} onChange={set('title')} placeholder="Ej.: agregar el aviso al segundo vendedor" />
            </label>
            <label style={{display:'flex',flexDirection:'column',gap:5}}>
              <span style={{fontSize:'0.76rem',color:'var(--text-dim)',fontWeight:600}}>Tipo</span>
              <select className="p-input p-select" value={f.type} onChange={set('type')}>
                <option value="consulta">Consulta general</option>
                <option value="aprobacion">Aprobación de un alcance</option>
                <option value="cambio">Solicitud de cambio</option>
                <option value="material">Entrega de accesos o datos</option>
              </select>
            </label>
            <label style={{display:'flex',flexDirection:'column',gap:5}}>
              <span style={{fontSize:'0.76rem',color:'var(--text-dim)',fontWeight:600}}>Detalle</span>
              <textarea className="p-input" rows={3} value={f.description} onChange={set('description')} style={{resize:'vertical',fontFamily:'inherit'}} placeholder="Opcional. Cuanto más concreto, más rápido lo resolvemos." />
            </label>
            <div style={{display:'flex',justifyContent:'flex-end'}}>
              <button className="p-btn p-btn-primary" onClick={send}>Enviar</button>
            </div>
          </div>
        )}

        <div className="p-card-pad">
          {reqs.length===0 ? <div className="p-empty"><b>Sin solicitudes todavía</b>Probalo con cualquier cosa: se responde igual.</div> : reqs.map(r=>(
            <div className="p-req" key={r.id}>
              <div className="p-req-row">
                <PBadge cls={REQ_STATUS_CLS[r.status]} label={REQ_STATUS_LABEL[r.status]} />
                <PBadge cls={REQ_TYPE_CLS[r.type]} label={REQ_TYPE_LABEL[r.type]} />
                <span style={{fontSize:'0.72rem',color:'var(--text-dim)',marginLeft:'auto'}}>{fmtDate(r.created_at)}</span>
              </div>
              <div className="p-req-title">{r.title}</div>
              {r.description && <div style={{fontSize:'0.8rem',color:'var(--text-soft)',marginTop:3}}>{r.description}</div>}
              {r.team_note && <div className="p-req-note"><b>Trascend:</b> {r.team_note}</div>}
            </div>
          ))}
        </div>
      </div>
      {toastNode}
    </div>
  );
}

/* =====================================================================
   MENSAJES — el historial de la conversación, sin buscar en el mail
   ===================================================================== */
function MensajesPage({ user }) {
  const threads = PortalData.getThreadsWithMessages(user.clientId) || [];
  const [open, setOpen] = useState(threads.length ? threads[0].id : null);
  const cur = threads.find(t=>t.id===open) || threads[0];

  if (!threads.length) return (
    <div className="p-card">
      <div className="p-card-head"><h3>Mensajes</h3></div>
      <div className="p-card-pad">
        <div className="p-empty"><b>Sin conversaciones todavía</b>Acá vas a ver el historial de lo que hablamos por WhatsApp y correo, sin tener que buscarlo.</div>
      </div>
    </div>
  );

  return (
    <div className="p-grid-2" style={{gridTemplateColumns:'minmax(220px,1fr) 2fr',alignItems:'start'}}>
      <div className="p-card">
        <div className="p-card-head"><h3>Conversaciones</h3></div>
        <div className="p-card-pad" style={{display:'flex',flexDirection:'column',gap:2}}>
          {threads.map(t=>(
            <button key={t.id} onClick={()=>setOpen(t.id)}
              style={{textAlign:'left',padding:'10px 12px',borderRadius:10,border:'1px solid '+(cur&&cur.id===t.id?'var(--violet)':'transparent'),
                      background:cur&&cur.id===t.id?'var(--violet-bg)':'transparent',cursor:'pointer',display:'flex',flexDirection:'column',gap:3}}>
              <span style={{display:'flex',alignItems:'center',gap:8}}>
                <span className="p-net-dot" style={{background:CH_COLOR[t.channel]||'#888',width:20,height:20,fontSize:'0.6rem'}}>{CH_LABEL[t.channel]||'?'}</span>
                <b style={{fontSize:'0.83rem'}}>{t.subject || (t.contact && t.contact.name) || 'Conversación'}</b>
              </span>
              <span style={{fontSize:'0.72rem',color:'var(--text-dim)'}}>{(t.messages||[]).length} mensaje(s)</span>
            </button>
          ))}
        </div>
      </div>

      <div className="p-card">
        <div className="p-card-head">
          <h3>{cur.subject || (cur.contact && cur.contact.name) || 'Conversación'}</h3><div className="sp"/>
          <span style={{fontSize:'0.74rem',color:'var(--text-dim)'}}>Solo lectura</span>
        </div>
        <div className="p-card-pad" style={{display:'flex',flexDirection:'column',gap:10}}>
          {(cur.messages||[]).map(m=>{
            const mine = m.direction === 'in';
            return (
              <div key={m.id} style={{alignSelf:mine?'flex-start':'flex-end',maxWidth:'82%',
                        background:mine?'var(--surface-2)':'var(--violet-bg)',
                        border:'1px solid var(--line-soft)',borderRadius:12,padding:'10px 13px'}}>
                <div style={{fontSize:'0.7rem',color:'var(--text-dim)',marginBottom:4,fontWeight:600}}>
                  {mine ? ((cur.contact && cur.contact.name) || 'Tu equipo') : 'Trascend'} · {fmtDT(m.sent_at)}
                </div>
                <div style={{fontSize:'0.85rem',lineHeight:1.55,whiteSpace:'pre-wrap'}}>{m.body}</div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   CONEXIONES — el cliente conecta sus canales; cross-sell silencioso
   ===================================================================== */
function ConnCard({ def, conn, user, onSaved, toast }) {
  const [open, setOpen]     = useState(false);
  const [ref, setRef]       = useState((conn && conn.account_ref) || '');
  const [tok, setTok]       = useState('');
  const [status, setStatus] = useState((conn && conn.status) || 'pending');
  const [busy, setBusy]     = useState(false);
  const st = CONN_STATUS[status] || CONN_STATUS.pending;
  const hasToken = !!(conn && conn.status === 'connected');
  async function save() {
    setBusy(true);
    await PortalData.saveConnection(user.clientId, def.channel, { account_ref: ref, token: tok, status });
    setBusy(false); setTok(''); setOpen(false); onSaved && onSaved(); toast('Conexión guardada');
  }
  return (
    <div className="p-card" style={{padding:'14px 16px'}}>
      <div style={{display:'flex',alignItems:'flex-start',gap:12}}>
        <div className="p-net-dot" style={{background:def.color,marginTop:2}}>{def.short}</div>
        <div style={{flex:1,minWidth:0}}>
          <div style={{display:'flex',alignItems:'center',gap:8,flexWrap:'wrap'}}>
            <b style={{fontSize:'0.9rem'}}>{def.name}</b>
            <PBadge cls={st.cls} label={st.label} />
          </div>
          <div style={{fontSize:'0.8rem',color:'var(--text-dim)',marginTop:2}}>{def.desc}</div>
          {open && (
            <div style={{marginTop:12,display:'flex',flexDirection:'column',gap:10}}>
              {def.fields.map(f=>(
                <div className="p-field" key={f.k}>
                  <label>{f.label}</label>
                  <input className="p-input" type={f.secret?'password':'text'}
                    value={f.k==='token'?tok:ref}
                    onChange={e=> f.k==='token'?setTok(e.target.value):setRef(e.target.value)}
                    placeholder={f.secret && hasToken ? '•••• (guardado — dejá vacío para no cambiarlo)' : (f.ph||'')} />
                </div>
              ))}
              <div className="p-field">
                <label>Estado</label>
                <select className="p-input p-select" value={status} onChange={e=>setStatus(e.target.value)}>
                  <option value="connected">Conectado (activo)</option>
                  <option value="pending">Sin conectar</option>
                  <option value="off">Desactivado</option>
                </select>
              </div>
              <div style={{fontSize:'0.72rem',color:'var(--text-dim)',display:'flex',alignItems:'center',gap:6}}>
                <PI.lock style={{width:13,height:13}} /> Tu credencial se guarda cifrada en el servidor y no se vuelve a mostrar.
              </div>
              <div style={{display:'flex',gap:8,justifyContent:'flex-end'}}>
                <button className="p-btn p-btn-ghost p-btn-sm" onClick={()=>{setOpen(false);setTok('');}}>Cancelar</button>
                <button className="p-btn p-btn-primary p-btn-sm" disabled={busy} onClick={save}><PI.check style={{width:14,height:14}} /> Guardar</button>
              </div>
            </div>
          )}
        </div>
        {!open && <button className="p-btn p-btn-ghost p-btn-sm" onClick={()=>setOpen(true)}>{hasToken?'Editar':'Configurar'}</button>}
      </div>
    </div>
  );
}

function ConexionesPage({ user }) {
  const [conns, setConns]  = useState(()=>PortalData.getConnections(user.clientId));
  const [sent, setSent]    = useState({});
  const [toast, toastNode] = useToast();
  const reload = ()=>setConns(PortalData.getConnections(user.clientId));
  const byCh = {}; conns.forEach(c=>byCh[c.channel]=c);
  const connected = conns.filter(c=>c.status==='connected').length;
  async function interested(svc){
    await PortalData.createRequest(user.clientId, user.contactId, { title:'Me interesa: '+svc.title, type:'consulta', description:'Solicitud de información sobre “'+svc.title+'” enviada desde el Portal.' });
    setSent(s=>({...s,[svc.title]:true})); toast('¡Listo! Un asesor de Trascend te va a contactar.');
  }
  return (
    <div className="p-stack">
      <div className="p-card">
        <div className="p-card-pad">
          <div style={{display:'flex',alignItems:'flex-start',gap:12,flexWrap:'wrap'}}>
            <div style={{flex:1,minWidth:220}}>
              <h2 style={{fontFamily:'var(--font-display)',fontSize:'1.1rem',fontWeight:800,letterSpacing:'-0.02em'}}>Conectá tus canales</h2>
              <p style={{fontSize:'0.84rem',color:'var(--text-soft)',marginTop:4,maxWidth:560}}>Cada canal que conectés es un lugar más donde <b>AGE</b> atiende solo: responde, registra el contacto y deriva a una persona cuando no sabe.</p>
            </div>
            <div style={{textAlign:'center',padding:'8px 16px',background:'var(--violet-bg)',borderRadius:12}}>
              <div style={{fontFamily:'var(--font-display)',fontSize:'1.7rem',fontWeight:800,color:'var(--violet)',lineHeight:1}}>{connected}</div>
              <div style={{fontSize:'0.66rem',color:'var(--text-dim)',textTransform:'uppercase',letterSpacing:'0.06em',marginTop:2}}>canales activos</div>
            </div>
          </div>
        </div>
      </div>

      <div className="p-grid-2">
        {CONN_CATALOG.map(def=> <ConnCard key={def.channel} def={def} conn={byCh[def.channel]} user={user} onSaved={reload} toast={toast} />)}
        <div className="p-card" style={{padding:'14px 16px'}}>
          <div style={{display:'flex',alignItems:'flex-start',gap:12}}>
            <div className="p-net-dot" style={{background:'#6D48C9',marginTop:2}}>◈</div>
            <div style={{flex:1}}>
              <div style={{display:'flex',alignItems:'center',gap:8,flexWrap:'wrap'}}><b style={{fontSize:'0.9rem'}}>Chat del sitio web</b><PBadge cls="pb-ok" label="Siempre activo" /></div>
              <div style={{fontSize:'0.8rem',color:'var(--text-dim)',marginTop:2}}>Ya viene incluido: el Closer responde en el chat de tu web sin configuración.</div>
            </div>
          </div>
        </div>
      </div>

      <div className="p-card" style={{background:'linear-gradient(135deg,var(--violet-bg),transparent)'}}>
        <div className="p-card-head"><PI.spark style={{width:16,height:16,color:'var(--violet)'}} /><h3 style={{marginLeft:6}}>Qué más podemos automatizar</h3></div>
        <div className="p-card-pad">
          <div className="p-grid-2" style={{gap:12}}>
            {CROSS_SELL.map(svc=>(
              <div key={svc.title} style={{display:'flex',flexDirection:'column',gap:6,padding:'13px 15px',border:'1px solid var(--line)',borderRadius:12,background:'var(--surface,#fff)'}}>
                <b style={{fontSize:'0.86rem'}}>{svc.title}</b>
                <span style={{fontSize:'0.79rem',color:'var(--text-dim)',flex:1}}>{svc.desc}</span>
                <button className="p-btn p-btn-ghost p-btn-sm" style={{alignSelf:'flex-start'}} disabled={!!sent[svc.title]} onClick={()=>interested(svc)}>
                  {sent[svc.title] ? '✓ Solicitado' : 'Me interesa'}
                </button>
              </div>
            ))}
          </div>
        </div>
      </div>
      {toastNode}
    </div>
  );
}

/* =====================================================================
   APP ROOT
   ===================================================================== */
function App() {
  const [ready, setReady] = useState(false);
  const [user,  setUser]  = useState(null);
  const [route, setRoute] = useState(()=>(location.hash.slice(1)||'inicio'));

  useEffect(()=>{
    PortalData.init().then(()=>{
      setUser(PortalAuth.current());
      setReady(true);
    });
  }, []);

  useEffect(()=>{
    const fn = ()=>setRoute(location.hash.slice(1)||'inicio');
    window.addEventListener('hashchange', fn);
    return ()=>window.removeEventListener('hashchange', fn);
  }, []);

  const navTo = r => { location.hash = r; };

  if (!ready) return null;
  if (!user)  return <LoginScreen onLogin={u=>{ setUser(u); navTo('inicio'); }} />;

  const reqs = PortalData.getRequests(user.clientId);
  const pendingReq = reqs.filter(r=>r.status!=='resuelta').length;

  const pages = {
    inicio:     <HomePage     user={user} setRoute={navTo} />,
    operacion:  <OperacionPage user={user} setRoute={navTo} />,
    proyectos:  <ProyectosPage user={user} />,
    conexiones: <ConexionesPage user={user} />,
    facturas:   <FacturasPage  user={user} />,
    peticiones: <PeticionesPage user={user} />,
    mensajes:   <MensajesPage  user={user} />,
  };

  return (
    <Shell user={user} route={route} setRoute={navTo} pendingReq={pendingReq}
      onLogout={()=>{
        PortalAuth.logout(); setUser(null);
        try { history.replaceState(null, '', location.pathname); }
        catch (e) { location.hash = ''; }
      }}>
      {pages[route] || pages.inicio}
    </Shell>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
