/* ============================================================
   SYMPHO — shared UI primitives + workspace chrome
   exports to window: Icon, Glyph, Avatar, NavCtx, useNav,
   AppRail, TopBar, CommandPalette, Stat, Section, Spark, Donut
   ============================================================ */

const { useState, useEffect, useRef, createContext, useContext } = React;

// ---------- navigation context ----------
const NavCtx = createContext(null);
const useNav = () => useContext(NavCtx);

// ---------- Icon ----------
function Icon({ name, size = 18, stroke = 1.8, style, className }) {
  const d = window.ICONS[name];
  if (!d) return null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth={stroke} strokeLinecap="round"
      strokeLinejoin="round" style={style} className={className}>
      {d.split("M").filter(Boolean).map((seg, i) => <path key={i} d={"M" + seg} />)}
    </svg>
  );
}

// ---------- app glyph (colored tile) ----------
function Glyph({ app, size = 40, radius }) {
  const r = radius != null ? radius : Math.round(size * 0.30);
  const fill = app.hue;
  return (
    <div className="glyph" style={{
      width: size, height: size, borderRadius: r,
      background: `linear-gradient(150deg, ${cx(fill, 1.12)}, ${cx(fill, 0.84)})`,
    }}>
      <Icon name={app.icon} size={size * 0.5} stroke={2} />
      {app.status === "soon" && (
        <span style={{
          position: "absolute", inset: 0, borderRadius: r,
          background: "var(--surface)", opacity: 0.55,
        }} />
      )}
    </div>
  );
}
// color helper — lighten/darken via oklch mix string
function cx(v, k) {
  if (k >= 1) return `color-mix(in oklch, ${v} ${Math.round((2 - k) * 100)}%, white)`;
  return `color-mix(in oklch, ${v} ${Math.round(k * 100)}%, black)`;
}

// ---------- avatar ----------
function Avatar({ name, initials, hue = "var(--sympho)", size = 30 }) {
  return (
    <div className="avatar" style={{
      width: size, height: size, fontSize: size * 0.38,
      background: `linear-gradient(150deg, ${cx(hue, 1.1)}, ${cx(hue, 0.82)})`,
    }} title={name}>{initials}</div>
  );
}

// ---------- section header ----------
function Section({ eyebrow, title, sub, right, style }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 16, ...style }}>
      <div>
        {eyebrow && <div className="eyebrow" style={{ marginBottom: 8 }}>{eyebrow}</div>}
        {title && <h2 className="disp" style={{ fontSize: 22, fontWeight: 600, letterSpacing: "-0.02em" }}>{title}</h2>}
        {sub && <p className="muted" style={{ fontSize: 13.5, marginTop: 5, maxWidth: 560 }}>{sub}</p>}
      </div>
      {right}
    </div>
  );
}

// ---------- stat tile ----------
function Stat({ icon, label, value, sub, hue = "var(--accent)", trend }) {
  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column", gap: 14, minWidth: 0 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <div style={{
          width: 34, height: 34, borderRadius: 9, display: "grid", placeItems: "center",
          background: `color-mix(in oklch, ${hue} 16%, transparent)`,
          color: hue, border: `1px solid color-mix(in oklch, ${hue} 30%, transparent)`,
        }}><Icon name={icon} size={17} /></div>
        {trend != null && (
          <span className="mono" style={{ fontSize: 12, color: trend >= 0 ? "var(--ok)" : "var(--bad)" }}>
            {trend >= 0 ? "+" : ""}{trend}%
          </span>
        )}
      </div>
      <div>
        <div className="disp" style={{ fontSize: 26, fontWeight: 600, letterSpacing: "-0.02em", lineHeight: 1 }}>{value}</div>
        <div className="muted" style={{ fontSize: 12.5, marginTop: 6 }}>{label}</div>
        {sub && <div className="mono" style={{ fontSize: 11, color: "var(--text-4)", marginTop: 3 }}>{sub}</div>}
      </div>
    </div>
  );
}

// ---------- mini sparkline ----------
function Spark({ data, hue = "var(--accent)", h = 40, w = 120, fill = true }) {
  const max = Math.max(...data), min = Math.min(...data);
  const rng = max - min || 1;
  const pts = data.map((v, i) => [ (i / (data.length - 1)) * w, h - ((v - min) / rng) * (h - 6) - 3 ]);
  const line = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L${w} ${h} L0 ${h} Z`;
  const gid = "g" + Math.random().toString(36).slice(2, 7);
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ display: "block" }}>
      <defs><linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stopColor={hue} stopOpacity="0.28" />
        <stop offset="1" stopColor={hue} stopOpacity="0" />
      </linearGradient></defs>
      {fill && <path d={area} fill={`url(#${gid})`} />}
      <path d={line} fill="none" stroke={hue} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ---------- donut ----------
function Donut({ segments, size = 132, thickness = 14, center }) {
  const total = segments.reduce((s, x) => s + x.n, 0) || 1;
  const r = (size - thickness) / 2;
  const c = 2 * Math.PI * r;
  let off = 0;
  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--surface-3)" strokeWidth={thickness} />
        {segments.map((s, i) => {
          const len = (s.n / total) * c;
          const el = <circle key={i} cx={size/2} cy={size/2} r={r} fill="none" stroke={s.hue}
            strokeWidth={thickness} strokeDasharray={`${len} ${c - len}`} strokeDashoffset={-off}
            strokeLinecap="butt" />;
          off += len; return el;
        })}
      </svg>
      {center && <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", textAlign: "center" }}>{center}</div>}
    </div>
  );
}

// ============================================================
//  APP RAIL — persistent ecosystem nav (left, 64px)
// ============================================================
function AppRail() {
  const nav = useNav();
  const active = window.APPS.filter(a => a.status === "active");
  const railItem = (key, icon, label, hue, on, onClick, glyph) => (
    <button key={key} className="rail-item" data-on={on} onClick={onClick} title={label}
      style={{ "--ind": hue || "var(--sympho)" }}>
      <span className="rail-ind" />
      {glyph || <Icon name={icon} size={21} />}
      <span className="rail-tip">{label}</span>
    </button>
  );
  return (
    <nav className="rail">
      <div className="rail-logo" onClick={() => nav.go({ view: "hub" })} title="Sympho">
        <Icon name="sparkle" size={20} stroke={1.6} />
      </div>
      <div className="rail-group">
        {railItem("hub", "home", "Inicio", "var(--sympho)", nav.loc.view === "hub", () => nav.go({ view: "hub" }))}
      </div>
      <div className="rail-sep" />
      <div className="rail-group">
        {active.map(a => railItem(a.id, a.icon, a.name, a.hue,
          nav.loc.view === "app" && nav.loc.appId === a.id,
          () => nav.openApp(a.id),
          <Glyph app={a} size={30} radius={9} />
        ))}
      </div>
      <div className="rail-sep" />
      <div className="rail-group">
        {railItem("modules", "layers", "Módulos", "var(--sympho)", nav.loc.view === "modules", () => nav.go({ view: "modules" }))}
        {railItem("admin", "shield", "Administración", "var(--sympho)", nav.loc.view === "admin", () => nav.go({ view: "admin" }))}
      </div>
      <div style={{ flex: 1 }} />
      <div className="rail-group" style={{ paddingBottom: 8 }}>
        <button className="rail-item" title={window.USER.name} onClick={() => nav.go({ view: "admin", sub: "members" })}>
          <Avatar name={window.USER.name} initials={window.USER.initials} hue={window.USER.hue} size={32} />
          <span className="rail-tip">{window.USER.name} · {window.USER.role}</span>
        </button>
      </div>
    </nav>
  );
}

// ============================================================
//  TOP BAR — workspace, search/command, app grid, alerts, user
// ============================================================
function TopBar({ onCommand }) {
  const nav = useNav();
  const [grid, setGrid] = useState(false);
  const [ws, setWs] = useState(false);
  const [menu, setMenu] = useState(false);
  const gref = useRef(), wref = useRef(), mref = useRef();
  useOutside([gref], () => setGrid(false));
  useOutside([wref], () => setWs(false));
  useOutside([mref], () => setMenu(false));

  const W = window.WORKSPACE;
  return (
    <header className="topbar">
      <div ref={wref} style={{ position: "relative" }}>
        <button className="ws-btn" onClick={() => setWs(v => !v)}>
          <span className="ws-mark"><Icon name="sparkle" size={14} stroke={1.6} /></span>
          <span style={{ display: "flex", flexDirection: "column", alignItems: "flex-start", lineHeight: 1.15 }}>
            <b style={{ fontSize: 13.5, fontWeight: 600 }}>{W.name}</b>
            <span className="mono" style={{ fontSize: 10.5, color: "var(--text-4)" }}>{W.domain}</span>
          </span>
          <Icon name="chevdown" size={15} style={{ color: "var(--text-4)", marginLeft: 2 }} />
        </button>
        {ws && (
          <div className="pop" style={{ left: 0, top: "calc(100% + 8px)", width: 280 }}>
            <div className="eyebrow" style={{ padding: "4px 10px 8px" }}>Workspace</div>
            <div className="pop-row" data-on="true">
              <span className="ws-mark" style={{ width: 30, height: 30 }}><Icon name="sparkle" size={15} stroke={1.6} /></span>
              <div style={{ flex: 1 }}>
                <b style={{ fontSize: 13 }}>{W.name}</b>
                <div className="mono" style={{ fontSize: 11, color: "var(--text-4)" }}>{W.plan}</div>
              </div>
              <Icon name="check" size={16} style={{ color: "var(--accent)" }} />
            </div>
            <div className="pop-row" style={{ opacity: 0.6 }}>
              <span className="ws-mark" style={{ width: 30, height: 30, background: "var(--surface-3)", color: "var(--text-3)" }}><Icon name="building" size={15} /></span>
              <div style={{ flex: 1 }}><b style={{ fontSize: 13 }}>KIO MEX4</b><div className="mono" style={{ fontSize: 11, color: "var(--text-4)" }}>Invitado · solo lectura</div></div>
            </div>
            <div className="pop-sep" />
            <div className="pop-row"><Icon name="plus" size={16} /><span style={{ fontSize: 13 }}>Crear workspace</span></div>
          </div>
        )}
      </div>

      <button className="cmd-btn" onClick={onCommand}>
        <Icon name="search" size={16} style={{ color: "var(--text-4)" }} />
        <span>Buscar o ejecutar comando…</span>
        <kbd>⌘K</kbd>
      </button>

      <div style={{ flex: 1 }} />

      <button className="ic-btn" title="Notificaciones"><Icon name="bell" size={18} /><span className="ic-dot" /></button>

      {window.EbLangSwitcher && <window.EbLangSwitcher />}
      {window.EbCopilotButton && <window.EbCopilotButton />}
      {window.EbChatToggle && <window.EbChatToggle />}

      <div ref={gref} style={{ position: "relative" }}>
        <button className="ic-btn" onClick={() => setGrid(v => !v)} data-on={grid} title="Aplicaciones"><Icon name="grid" size={18} /></button>
        {grid && <AppGrid onPick={(a) => { setGrid(false); a.status === "active" ? nav.openApp(a.id) : nav.go({ view: "app", appId: a.id }); }} />}
      </div>

      <div ref={mref} style={{ position: "relative" }}>
        <button onClick={() => setMenu(v => !v)} style={{ background: "none", border: "none", cursor: "pointer", padding: 2, borderRadius: 999 }}>
          <Avatar name={window.USER.name} initials={window.USER.initials} hue={window.USER.hue} size={32} />
        </button>
        {menu && (
          <div className="pop" style={{ right: 0, top: "calc(100% + 8px)", width: 232 }}>
            <div style={{ display: "flex", gap: 10, alignItems: "center", padding: "6px 8px 12px" }}>
              <Avatar name={window.USER.name} initials={window.USER.initials} hue={window.USER.hue} size={38} />
              <div style={{ minWidth: 0 }}>
                <b style={{ fontSize: 13, display: "block" }}>{window.USER.name}</b>
                <span className="mono" style={{ fontSize: 11, color: "var(--text-4)" }}>{window.USER.email}</span>
              </div>
            </div>
            <div className="pop-sep" />
            <div className="pop-row" onClick={() => { setMenu(false); nav.go({ view: "admin", sub: "members" }); }}><Icon name="users" size={16} /><span style={{ fontSize: 13 }}>Administración</span></div>
            <div className="pop-row" onClick={() => { setMenu(false); nav.go({ view: "modules" }); }}><Icon name="layers" size={16} /><span style={{ fontSize: 13 }}>Módulos & plan</span></div>
            <div className="pop-row"><Icon name="settings" size={16} /><span style={{ fontSize: 13 }}>Preferencias</span></div>
            <div className="pop-sep" />
            <div className="pop-row" onClick={() => nav.go({ view: "login" })}><Icon name="logout" size={16} /><span style={{ fontSize: 13 }}>Cerrar sesión</span></div>
          </div>
        )}
      </div>
    </header>
  );
}

// ---------- Google-style app launcher grid ----------
function AppGrid({ onPick }) {
  return (
    <div className="pop grid-pop">
      <div className="eyebrow" style={{ padding: "2px 6px 12px" }}>Aplicaciones · Sympho</div>
      <div className="app-grid">
        {window.APPS.map(a => (
          <button key={a.id} className="app-cell" onClick={() => onPick(a)} disabled={a.status === "soon"}>
            <Glyph app={a} size={46} />
            <span style={{ fontSize: 12, fontWeight: 500 }}>{a.name}</span>
            <span className="mono" style={{ fontSize: 9.5, color: "var(--text-4)" }}>{a.status === "soon" ? "Pronto" : a.tag}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

// ---------- Command palette ----------
function CommandPalette({ open, onClose }) {
  const nav = useNav();
  const [q, setQ] = useState("");
  const inp = useRef();
  useEffect(() => { if (open) { setQ(""); setTimeout(() => inp.current && inp.current.focus(), 30); } }, [open]);
  if (!open) return null;

  const cmds = [];
  cmds.push({ group: "Ir a", icon: "home", label: "Inicio", run: () => nav.go({ view: "hub" }) });
  cmds.push({ group: "Ir a", icon: "layers", label: "Módulos & activación", run: () => nav.go({ view: "modules" }) });
  cmds.push({ group: "Ir a", icon: "shield", label: "Administración · Miembros", run: () => nav.go({ view: "admin", sub: "members" }) });
  cmds.push({ group: "Ir a", icon: "lock", label: "Administración · Permisos", run: () => nav.go({ view: "admin", sub: "perms" }) });
  window.APPS.forEach(a => cmds.push({ group: "Abrir app", icon: a.icon, label: a.name + " — " + a.tag, hue: a.hue, run: () => a.status === "active" && nav.openApp(a.id), dim: a.status === "soon" }));
  cmds.push({ group: "Acción", icon: "plus", label: "Nueva factura (Muluk)", hue: "var(--muluk)", run: () => nav.openApp("muluk", "new") });
  cmds.push({ group: "Acción", icon: "camera", label: "Captura en campo (Manik)", hue: "var(--manik)", run: () => nav.openApp("manik", "field") });
  cmds.push({ group: "Acción", icon: "sparkle", label: "Preguntar a K'in Copilot (IA)", hue: "var(--kin)", run: () => nav.openApp("kin", "copilot") });
  cmds.push({ group: "Acción", icon: "node", label: "Abrir Digital Twin (K'in)", hue: "var(--kin)", run: () => nav.openApp("kin", "twin") });
  cmds.push({ group: "Acción", icon: "plus", label: "Invitar miembro", run: () => nav.go({ view: "admin", sub: "members" }) });

  const filt = cmds.filter(c => (c.label + c.group).toLowerCase().includes(q.toLowerCase()));
  const groups = [...new Set(filt.map(c => c.group))];

  return (
    <div className="cmd-overlay" onMouseDown={onClose}>
      <div className="cmd-panel" onMouseDown={e => e.stopPropagation()}>
        <div className="cmd-input">
          <Icon name="search" size={18} style={{ color: "var(--text-4)" }} />
          <input ref={inp} value={q} onChange={e => setQ(e.target.value)} placeholder="Buscar apps, registros o comandos…" />
          <kbd>esc</kbd>
        </div>
        <div className="cmd-list scroll">
          {groups.map(g => (
            <div key={g}>
              <div className="eyebrow" style={{ padding: "12px 14px 6px" }}>{g}</div>
              {filt.filter(c => c.group === g).map((c, i) => (
                <button key={i} className="cmd-row" disabled={c.dim} onClick={() => { c.run(); onClose(); }}>
                  <span style={{ color: c.hue || "var(--text-2)" }}><Icon name={c.icon} size={17} /></span>
                  <span style={{ flex: 1, textAlign: "left", fontSize: 13.5 }}>{c.label}</span>
                  <Icon name="arrowr" size={15} style={{ color: "var(--text-4)" }} />
                </button>
              ))}
            </div>
          ))}
          {!filt.length && <div className="muted" style={{ padding: 24, textAlign: "center", fontSize: 13 }}>Sin resultados para "{q}"</div>}
        </div>
      </div>
    </div>
  );
}

// ---------- click-outside hook ----------
function useOutside(refs, cb) {
  useEffect(() => {
    const h = (e) => { if (refs.every(r => r.current && !r.current.contains(e.target))) cb(); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  });
}

Object.assign(window, { Icon, Glyph, Avatar, NavCtx, useNav, AppRail, TopBar, AppGrid, CommandPalette, Section, Stat, Spark, Donut, cx, useOutside });
