// BetyChef — Shared components
const { useState, useEffect, useRef, useMemo } = React;

/* ── Global test-data toggle hook ──
   Single source of truth: window.BC._showTestData (+ localStorage).
   Any component using this re-renders when the toggle flips anywhere. */
function useShowTestData() {
  const [show, setShow] = useState(
    window.BC_testAccounts ? window.BC_testAccounts.getShow() : false
  );
  useEffect(() => {
    const sync = () => setShow(window.BC_testAccounts.getShow());
    window.addEventListener("showTestDataChanged", sync);
    window.addEventListener("testAccountsChanged", sync);
    return () => {
      window.removeEventListener("showTestDataChanged", sync);
      window.removeEventListener("testAccountsChanged", sync);
    };
  }, []);
  return show;
}

/* ── Global light/dark theme toggle ──
   Single source of truth: localStorage "betychef_theme" (+ window.BC_theme).
   Works independently of the edit-mode Tweaks panel, so it's reachable from
   the real, deployed dashboard — not just the design-tool host. */
window.BC_theme = {
  get: () => localStorage.getItem("betychef_theme") || "light",
  set: (theme) => {
    localStorage.setItem("betychef_theme", theme);
    document.documentElement.dataset.theme = theme;
    window.dispatchEvent(new Event("themeChanged"));
  },
  toggle: () => window.BC_theme.set(window.BC_theme.get() === "dark" ? "light" : "dark"),
};

function useTheme() {
  const [theme, setTheme] = useState(window.BC_theme.get());
  useEffect(() => {
    const sync = () => setTheme(window.BC_theme.get());
    window.addEventListener("themeChanged", sync);
    return () => window.removeEventListener("themeChanged", sync);
  }, []);
  return theme;
}

function ThemeToggle() {
  const theme = useTheme();
  const isDark = theme === "dark";
  return (
    <button className="bc-icon-btn" onClick={() => window.BC_theme.toggle()}
      title={isDark ? "Switch to light mode" : "Switch to dark mode"}>
      <Icon name={isDark ? "sun" : "moon"} size={19}/>
    </button>
  );
}

/* ── The one global LIVE/TEST toggle (lives in the topbar) ── */
function TestDataToggle() {
  const show = useShowTestData();
  return (
    <button
      className="bc-testtoggle"
      onClick={() => window.BC_testAccounts.toggleShow()}
      title={show ? "Currently showing test data — click for LIVE only" : "Live data only — click to reveal test data"}
      data-on={show ? "1" : "0"}>
      <span className="bc-testtoggle-dot"/>
      {show ? "TEST" : "LIVE"}
    </button>
  );
}

/* ── Permissions hook ──
   Re-renders consumers when the logged-in role or preview role changes.
   Exposes can(section,action), the effective role, and preview state. */
function usePermissions() {
  const [, force] = useState(0);
  useEffect(() => {
    const sync = () => force(n => n + 1);
    window.addEventListener("previewRoleChanged", sync);
    window.addEventListener("teamAccessChanged", sync);
    return () => {
      window.removeEventListener("previewRoleChanged", sync);
      window.removeEventListener("teamAccessChanged", sync);
    };
  }, []);
  const ta = window.BC_teamAccess;
  if (!ta) return { can: () => true, role: "founder", previewing: false, isFounder: true };
  const eff = ta.getEffective();
  return {
    can: (s, a) => ta.can(s, a),
    role: eff.role,
    name: eff.name,
    previewing: eff.previewing,
    previewMemberId: eff.previewMemberId || null,
    isFounder: ta.isFounder(),
  };
}

/* ── Field-level redaction ──
   Wraps a sensitive value (commission, payout, contact info). Renders the
   real value if the viewer has the matching `sensitive.*` permission,
   otherwise a small locked placeholder instead — used inline in tables,
   stat cards and detail popups so hiding data doesn't mean hiding screens. */
function Gate({ need, action, children, label }) {
  const { can } = usePermissions();
  if (can(need, action)) return children;
  return <span className="bc-redacted" title={label || "Hidden by your permissions"}><Icon name="key" size={11}/>•••</span>;
}

/* ── Floating "viewing as <member>" bar ──
   Founder-only. Mounted once at the app root so it travels with you to
   every screen while a preview is active. The dropdown lets you switch
   who you're viewing as without closing it; the × button ends the preview
   and sends you back to Team access — its natural home. */
function TeamPreviewBar({ navigate }) {
  const { isFounder, previewing, name, previewMemberId } = usePermissions();
  if (!isFounder || !previewing) return null;

  const members = window.BC_teamAccess.listPreviewable();

  function switchTo(id) {
    if (!id) return;
    window.BC_teamAccess.setPreviewMember(id);
  }
  function close() {
    window.BC_teamAccess.setPreviewMember(null);
    navigate && navigate("settings");
  }

  return (
    <div className="bc-preview-float">
      <span className="bc-preview-float-dot"/>
      <Icon name="eye" size={15}/>
      <span className="bc-preview-float-label">Viewing as <b>{name}</b></span>
      <select className="bc-preview-float-select" value={previewMemberId || ""} onChange={e=>switchTo(e.target.value)}>
        {members.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
      </select>
      <button className="bc-preview-float-close" onClick={close} title="Exit preview — back to Team access">
        <Icon name="x" size={14} stroke={2.4}/>
      </button>
    </div>
  );
}

// Map a nav id → the permission needed to see it
const NAV_PERMISSION = {
  overview:  ["analytics", "view"],
  orders:    ["orders", "view"],
  chefs:     ["chefs", "view"],
  applications: ["chefs", "view"],
  dishes:    ["dishes", "view"],
  customers: ["customers", "view"],
  ops:       ["sensitive", "viewFinancials"],   // entire page is revenue/commission — gate the whole thing
  notify:    ["notifications", "view"],
  crm:       ["outreach", "view"],
  controls:  ["controls", "view"],   // founder/admin only
  settings:  ["team", "view"],       // founder/admin only
};

// Whether a screen should appear in nav / be reachable at all — combines the
// founder's explicit per-screen on/off switch (permissions.screens.<id>)
// with the existing functional permission for that section. Both must pass.
// "controls"/"settings" are NOT togglable screens (founder/admin-only, hard
// boundary) — can("screens", id) coerces a missing key to false via !!, so
// those two must skip the screens gate entirely rather than reading that
// coercion as "blocked".
const NON_TOGGLABLE_SCREENS = ["controls", "settings"];
function canSeeScreen(can, id) {
  const screensOk = NON_TOGGLABLE_SCREENS.includes(id) || can("screens", id) !== false;
  const perm = NAV_PERMISSION[id];
  return screensOk && (!perm || can(perm[0], perm[1]));
}

/* ── Icons ── */
const PATHS = {
  overview:  "M4 13h6V4H4v9Zm0 7h6v-5H4v5Zm9 0h7v-9h-7v9Zm0-16v5h7V4h-7Z",
  chefs:     "M7 11a5 5 0 0 1 10 0M5 12h14v3a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3v-3Zm4-1V8m3 3V7m3 4V8M9 22h6",
  orders:    "M6 2h9l3 3v17l-2.5-1.5L13 22l-2.5-1.5L8 22l-2-1.5L6 22V2Zm3 6h6M9 12h6M9 16h4",
  customers: "M16 19v-1a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v1m13.5-7a4 4 0 1 0-4-7M9.5 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm11 8v-1a4 4 0 0 0-3-3.87",
  ops:       "M12 2v3m6.4 1.6-2.1 2.1M22 12h-3m-1.6 6.4-2.1-2.1M12 22v-3m-6.4-1.6 2.1-2.1M2 12h3m1.6-6.4 2.1 2.1M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z",
  controls:  "M4 6h11M4 12h7M4 18h13M17 4v4M11 10v4M20 16v4",
  notify:    "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0",
  crm:       "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z",
  truck:     "M1 5h14v10H1V5Zm14 4h4l3 3v3h-7V9ZM6 18a2 2 0 1 0 0 0Zm12 0a2 2 0 1 0 0 0Z",
  card:      "M2 6h20v12H2V6Zm0 4h20",
  money:     "M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6",
  search:    "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm10 2-4.3-4.3",
  check:     "M20 6 9 17l-5-5",
  verify:    "M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5l-8-3Zm-1.5 9.5L9 10l-1.4 1.4L10.5 14 16 8.5 14.6 7l-4.1 4.5Z",
  x:         "M18 6 6 18M6 6l12 12",
  chevron:   "M9 18l6-6-6-6",
  dish:      "M3 12a9 9 0 0 1 18 0M2 12h20M12 3v1.5M5.5 16h13",
  "chevron-left":  "M15 18l-6-6 6-6",
  "chevron-right": "M9 18l6-6-6-6",
  "chevron-up":    "M18 15l-6-6-6 6",
  sliders:   "M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6",
  dot:       "M12 12h.01",
  alert:     "M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z",
  star:      "M12 3l2.7 5.5 6 .9-4.3 4.2 1 6L12 17.8 6.6 19.6l1-6L3.3 9.4l6-.9L12 3Z",
  plus:      "M12 5v14M5 12h14",
  send:      "M22 2 11 13M22 2l-7 20-4-9-9-4 20-7Z",
  broadcast: "M3 11v2a1 1 0 0 0 1 1h2l5 4V6L6 10H4a1 1 0 0 0-1 1Zm13-3a5 5 0 0 1 0 8m2.5-11a9 9 0 0 1 0 14",
  pin:       "M12 21s-7-6.4-7-11a7 7 0 1 1 14 0c0 4.6-7 11-7 11Zm0-8.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z",
  pause:     "M8 5h3v14H8zM13 5h3v14h-3z",
  clock:     "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0-14v5l3 2",
  trash:     "M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6m5 4v6m4-6v6",
  edit:      "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5Z",
  eye:       "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8Zm11-3a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z",
  "eye-off": "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24M1 1l22 22",
  phone:     "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92Z",
  signout:   "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9",
  key:       "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4",
  user:      "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z",
  team:      "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm14 10v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",
  download:  "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3",
  chart:     "M18 20V10M12 20V4M6 20v-6",
  sun:       "M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10ZM12 1v3M12 20v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M1 12h3M20 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1",
  moon:      "M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8Z",
};

function Icon({ name, size = 20, stroke = 1.7, fill = "none", style }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}
      stroke="currentColor" strokeWidth={stroke}
      strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...style }}>
      <path d={PATHS[name] || ""} />
    </svg>
  );
}

/* ── Nav ── */
// Flat list of every leaf view (used by MobileNav, global search, routing)
const NAV = [
  { id: "overview",     label: "Home",          icon: "overview"  },
  { id: "orders",       label: "Orders",        icon: "orders"    },
  { id: "chefs",        label: "Chef network",  icon: "chefs"     },
  { id: "applications", label: "Applications",  icon: "verify"    },
  { id: "dishes",       label: "Dishes",        icon: "dish"      },
  { id: "customers",    label: "Customers",     icon: "customers" },
  { id: "ops",          label: "Operations",    icon: "ops"       },
  { id: "crm",          label: "Prospects",     icon: "crm"       },
  { id: "notify",       label: "Notifications", icon: "notify"    },
  { id: "controls",     label: "Controls",      icon: "controls"  },
  { id: "settings",     label: "Team access",   icon: "team"      },
];

// Grouped structure for the sidebar — single items + collapsible groups.
const NAV_GROUPS = [
  { type:"item",  id:"overview",  label:"Home",       icon:"overview"  },
  { type:"item",  id:"orders",    label:"Orders",     icon:"orders"    },
  { type:"group", id:"g-chefs",   label:"Chefs",      icon:"chefs", children:[
      { id:"chefs",        label:"Chef network", icon:"chefs"  },
      { id:"applications", label:"Applications", icon:"verify" },
      { id:"dishes",       label:"Dishes",       icon:"dish"   },
  ]},
  { type:"item",  id:"customers", label:"Customers",  icon:"customers" },
  { type:"item",  id:"ops",       label:"Operations", icon:"ops"       },
  { type:"group", id:"g-outreach", label:"Outreach",  icon:"crm", children:[
      { id:"crm",    label:"Prospects",     icon:"crm"    },
      { id:"notify", label:"Notifications", icon:"notify" },
  ]},
  { type:"group", id:"g-settings", label:"Settings",  icon:"controls", children:[
      { id:"controls", label:"Controls",    icon:"controls" },
      { id:"settings", label:"Team access", icon:"team"     },
  ]},
];

/* ── Sidebar goal ring (celebratory progress bar) ── */
function SideGoalRing({ value, goal }) {
  const frac = Math.min((value || 0) / (goal || 100), 1);
  const remaining = (goal || 100) - (value || 0);
  const isClose = frac >= 0.6;  // Celebrate when 60% there
  const isVeryClose = frac >= 0.8;  // Extra celebration at 80%

  // Milestone messages based on progress
  let milestone = "";
  if (frac < 0.3) milestone = `${remaining} to go • keep building`;
  else if (frac < 0.5) milestone = `${remaining} to go • halfway there`;
  else if (frac < 0.7) milestone = `${remaining} to go • almost there`;
  else if (frac < 0.85) milestone = `${remaining} to go • so close!`;
  else if (frac < 1) milestone = `${remaining} to go • you're crushing it 🔥`;
  else milestone = "🎉 Goal reached!";

  // Color intensity increases as you get closer
  let progressColor = "var(--c-primary)";
  let glowColor = "rgba(6,208,1,.3)";
  if (isVeryClose) {
    progressColor = "#10B981";
    glowColor = "rgba(16,185,129,.6)";
  } else if (isClose) {
    progressColor = "#06D001";
    glowColor = "rgba(6,208,1,.5)";
  }

  return (
    <div style={{ textAlign: "center", padding: "16px 12px", background: "var(--c-surface-2)", borderRadius: "14px" }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: "var(--c-ink-2)", textTransform: "uppercase", letterSpacing: ".04em", marginBottom: "10px" }}>
        🏆 Milestone 1
      </div>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "center", gap: "4px", marginBottom: "8px" }}>
        <div style={{ fontFamily: "var(--font-head)", fontWeight: 700, fontSize: "28px", color: "var(--c-ink)" }}>
          {value}
        </div>
        <div style={{ fontSize: "14px", color: "var(--c-ink-2)" }}>/ {goal || 100} chefs</div>
      </div>

      {/* Progress bar */}
      <div style={{
        height: "8px",
        background: "var(--c-surface)",
        borderRadius: "4px",
        overflow: "hidden",
        marginBottom: "8px",
        boxShadow: "inset 0 1px 2px rgba(0,0,0,.1)"
      }}>
        <div style={{
          height: "100%",
          width: `${(frac * 100).toFixed(1)}%`,
          background: progressColor,
          borderRadius: "4px",
          transition: "width .6s ease-out",
          boxShadow: `0 0 8px ${glowColor}`,
          animation: isVeryClose ? "pulse 2s infinite" : "none"
        }} />
      </div>

      {/* Milestone message */}
      <div style={{
        fontSize: "12px",
        color: "var(--c-ink-2)",
        fontWeight: 500,
        lineHeight: "1.4"
      }}>
        {milestone}
      </div>
    </div>
  );
}

/* ── Sidebar ── */
function Sidebar({ view, setView, minimized, onToggleSidebar }) {
  const ns = window.BC.northStar || {};
  const { can } = usePermissions();
  // Accordion: only one group open at a time. Whichever group holds the
  // active view opens automatically (and closes whatever else was open).
  const [openGroup, setOpenGroup] = useState(() => {
    const g = NAV_GROUPS.find(e => e.type === "group" && e.children.some(k => k.id === view));
    return g ? g.id : null;
  });
  useEffect(() => {
    const g = NAV_GROUPS.find(e => e.type === "group" && e.children.some(k => k.id === view));
    if (g) setOpenGroup(g.id);
  }, [view]);
  return (
    <aside className={"bc-sidebar" + (minimized ? " is-minimized" : "")}>
      <div className="bc-brand">
        <div className="bc-brand-mark">
          <img src="assets/logo.jpg" alt="BetyChef" />
        </div>
        <div className="bc-brand-text">
          <div className="bc-brand-name">BetyChef</div>
          <div className="bc-brand-sub">Founder Console</div>
        </div>
      </div>
      <nav className="bc-nav">
        <button className="bc-sidebar-toggle-nav" onClick={onToggleSidebar} title={minimized ? "Expand sidebar" : "Collapse sidebar"} style={{fontSize: "16px"}}>
          <span style={{marginRight: "6px"}}>{minimized ? "👉" : "👈"}</span>
          <Icon name={minimized ? "chevron-right" : "chevron-left"} size={18}/>
          <span>{minimized ? "Expand" : "Collapse"}</span>
        </button>

        {NAV_GROUPS.map(entry => {
          // ── single item ──
          if (entry.type === "item") {
            if (!canSeeScreen(can, entry.id)) return null;
            return (
              <button key={entry.id}
                className={"bc-nav-item" + (view === entry.id ? " is-active" : "")}
                onClick={() => setView(entry.id)}>
                <Icon name={entry.icon} size={20} />
                <span>{entry.label}</span>
                {entry.id === "orders" && <span className="bc-nav-dot-live" />}
              </button>
            );
          }

          // ── collapsible group ──
          const kids = entry.children.filter(k => canSeeScreen(can, k.id));
          if (!kids.length) return null;

          const activeInGroup = kids.some(k => k.id === view);
          const isOpen = openGroup === entry.id;
          // group-level badge (e.g. pending applications surfaced on Chefs)
          const groupBadge = entry.id === "g-chefs" ? (ns.pending || 0) : 0;

          return (
            <div key={entry.id} className="bc-nav-group">
              <button
                className={"bc-nav-item bc-nav-parent" + (activeInGroup ? " has-active" : "")}
                onClick={() => setOpenGroup(isOpen ? null : entry.id)}>
                <Icon name={entry.icon} size={20} />
                <span>{entry.label}</span>
                {groupBadge > 0 && <span className="bc-nav-badge">{groupBadge}</span>}
                <Icon name={isOpen ? "chevron-up" : "chevron"} size={15}
                  style={{ marginLeft: groupBadge>0?6:"auto", opacity:.5, transform: isOpen?"none":"rotate(90deg)" }} />
              </button>
              {isOpen && (
                <div className="bc-nav-children">
                  {kids.map(k => (
                    <button key={k.id}
                      className={"bc-nav-item bc-nav-sub" + (view === k.id ? " is-active" : "")}
                      onClick={() => setView(k.id)}>
                      <Icon name={k.icon} size={17} />
                      <span>{k.label}</span>
                      {k.id === "applications" && (ns.pending || 0) > 0 &&
                        <span className="bc-nav-badge">{ns.pending}</span>}
                    </button>
                  ))}
                </div>
              )}
            </div>
          );
        })}
      </nav>

      {/* Milestone ring */}
      <div className="bc-side-foot">
        <div className="bc-side-ring-card">
          <div className="bc-side-ring-label">Race to 100 chefs</div>
          <SideGoalRing value={ns.active || 0} goal={ns.goal || 100} />
          <div className="bc-sp-bar" style={{ marginTop:10 }}>
            <div style={{ flex: Math.max(ns.active||0,.01), background:"var(--c-green)"  }} />
            <div style={{ flex: Math.max(ns.joined||0,.01), background:"var(--c-saffron)"}} />
            <div style={{ flex: Math.max(ns.paused||0,.01), background:"var(--c-line-2)" }} />
          </div>
          <div className="bc-sp-legend">
            <span><i style={{background:"var(--c-green)"}}/>Active {ns.active||0}</span>
            <span><i style={{background:"var(--c-saffron)"}}/>Joined {ns.joined||0}</span>
            <span><i style={{background:"var(--c-line-2)"}}/>Paused {ns.paused||0}</span>
          </div>
        </div>
      </div>
    </aside>
  );
}

/* ── Activity bell dropdown ── */
function ActivityBell() {
  const [open, setOpen] = useState(false);
  const [teamActivity, setTeamActivity] = useState([]);
  const ref = useRef(null);

  useEffect(() => {
    function outside(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    if (open) document.addEventListener("mousedown", outside);
    return () => document.removeEventListener("mousedown", outside);
  }, [open]);

  useEffect(() => {
    const loadTeamActivity = () => {
      if (window.BC_teamAccess) {
        setTeamActivity(window.BC_teamAccess.getActivity().slice(0, 15));
      }
    };
    loadTeamActivity();
    window.addEventListener("teamAccessChanged", loadTeamActivity);
    return () => window.removeEventListener("teamAccessChanged", loadTeamActivity);
  }, []);

  const activity = (window.BC.activity || []).slice(0, 8);
  const actIcon = { verify:"verify", order:"orders", delivery:"truck", milestone:"star",
    payment:"card", apply:"chefs", remove:"x" };

  // count items from last 60 minutes as "new"
  const newCount = useMemo(() => {
    const cutoff = Date.now() - 3600000;
    return (window.BC.orders || []).filter(o => {
      if (!o.createdAt) return false;
      const d = o.createdAt.toDate ? o.createdAt.toDate() : new Date(o.createdAt);
      return d.getTime() > cutoff;
    }).length;
  }, [window.BC.orders]);

  // Merge both activity types chronologically
  const mergedActivity = useMemo(() => {
    const teamItems = teamActivity.map(log => ({
      type: 'team',
      description: log.description,
      timestamp: new Date(log.timestamp),
      timeStr: new Date(log.timestamp).toLocaleString()
    }));
    const liveItems = activity.map(a => ({
      type: 'live',
      ...a,
      timestamp: a.createdAt ? (a.createdAt.toDate ? a.createdAt.toDate() : new Date(a.createdAt)) : new Date()
    }));
    return [...teamItems, ...liveItems].sort((a, b) => (b.timestamp?.getTime?.() || 0) - (a.timestamp?.getTime?.() || 0)).slice(0, 12);
  }, [teamActivity, activity]);

  const totalCount = teamActivity.length + newCount;

  return (
    <div className="bc-bell-wrap" ref={ref}>
      <button className="bc-icon-btn" onClick={() => setOpen(!open)} title="All activity">
        <Icon name="notify" size={20} />
        {totalCount > 0 && <span className="bc-icon-dot">{totalCount > 9 ? "9+" : totalCount}</span>}
      </button>
      {open && (
        <div className="bc-bell-dropdown">
          <div className="bc-bell-head">
            <span>All activity</span>
            <span className="bc-livepill"><span className="bc-livedot"/>Live</span>
          </div>
          {mergedActivity.length === 0 ? (
            <div className="bc-bell-empty">No activity yet</div>
          ) : (
            mergedActivity.map((item, i) => (
              item.type === 'team' ? (
                <div key={i} className="bc-bell-item" style={{padding:"12px 16px",borderBottom:"1px solid var(--c-line)",background:"var(--c-surface-2)"}}>
                  <div style={{fontSize:13,fontWeight:600,marginBottom:4}}>👥 {item.description}</div>
                  <div style={{fontSize:11,color:"var(--c-ink-2)"}}>{item.timeStr}</div>
                </div>
              ) : (
                <div key={i} className="bc-bell-item">
                  <span className={"bc-feed-ic bc-feed-ic--"+(item.type||"order")} style={{flexShrink:0}}>
                    <Icon name={actIcon[item.type]||"dot"} size={14} stroke={2}/>
                  </span>
                  <span className="bc-bell-text"><b>{item.who}</b> {item.what}</span>
                  <span className="bc-bell-when">{item.when}</span>
                </div>
              )
            ))
          )}
        </div>
      )}
    </div>
  );
}

/* ── Profile menu ── */
function ProfileMenu() {
  const [open,    setOpen]    = useState(false);
  const [mode,    setMode]    = useState("menu");   // menu | pwd | name
  const [newPwd,  setNewPwd]  = useState("");
  const [confirm, setConfirm] = useState("");
  const [newName, setNewName] = useState("");
  const [msg,     setMsg]     = useState("");
  const ref = useRef(null);

  const user = firebase.auth().currentUser;
  const displayName = user?.displayName || user?.email?.split("@")[0] || "Founder";

  useEffect(() => {
    function outside(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    if (open) document.addEventListener("mousedown", outside);
    return () => document.removeEventListener("mousedown", outside);
  }, [open]);

  async function changePwd(e) {
    e.preventDefault();
    if (newPwd !== confirm) return setMsg("Passwords don't match");
    if (newPwd.length < 6)  return setMsg("Min 6 characters");
    try {
      await firebase.auth().currentUser.updatePassword(newPwd);
      setMsg("Password updated ✓");
      setTimeout(() => { setMode("menu"); setMsg(""); setNewPwd(""); setConfirm(""); }, 1500);
    } catch(err) { setMsg(err.message); }
  }

  async function changeName(e) {
    e.preventDefault();
    if (!newName.trim()) return setMsg("Enter a name");
    try {
      await firebase.auth().currentUser.updateProfile({ displayName: newName.trim() });
      setMsg("Name updated ✓");
      setTimeout(() => { setMode("menu"); setMsg(""); setNewName(""); }, 1500);
    } catch(err) { setMsg(err.message); }
  }

  const initials = displayName.slice(0,2).toUpperCase();

  return (
    <div className="bc-profile-wrap" ref={ref}>
      <button className="bc-me" onClick={() => { setOpen(!open); setMode("menu"); setMsg(""); }}
        title={user?.email}>{initials}</button>
      {open && (
        <div className="bc-profile-menu">
          {mode === "menu" && (
            <>
              <div className="bc-pm-header">
                <div className="bc-pm-name">{displayName}</div>
                <div className="bc-pm-email">{user?.email}</div>
                <div className="bc-pm-role">Founder · BetyChef</div>
              </div>
              <button className="bc-pm-item" onClick={() => { setNewName(displayName); setMode("name"); }}>
                <Icon name="user" size={15}/>Change name
              </button>
              <button className="bc-pm-item" onClick={() => setMode("pwd")}>
                <Icon name="key" size={15}/>Change password
              </button>
              <div className="bc-pm-divider"/>
              <button className="bc-pm-item bc-pm-item--danger" onClick={() => firebase.auth().signOut()}>
                <Icon name="signout" size={15}/>Sign out
              </button>
            </>
          )}
          {mode === "name" && (
            <form className="bc-pm-form" onSubmit={changeName}>
              <button type="button" className="bc-pm-back" onClick={() => setMode("menu")}>← Back</button>
              <input className="bc-input bc-input--sm" value={newName}
                onChange={e => setNewName(e.target.value)} placeholder="Your display name" autoFocus/>
              {msg && <div className="bc-pm-msg">{msg}</div>}
              <button className="bc-btn bc-btn--primary" type="submit"
                style={{width:"100%",height:38,fontSize:13}}>Save name</button>
            </form>
          )}
          {mode === "pwd" && (
            <form className="bc-pm-form" onSubmit={changePwd}>
              <button type="button" className="bc-pm-back" onClick={() => setMode("menu")}>← Back</button>
              <input className="bc-input bc-input--sm" type="password" placeholder="New password"
                value={newPwd} onChange={e => setNewPwd(e.target.value)} autoFocus/>
              <input className="bc-input bc-input--sm" type="password" placeholder="Confirm password"
                value={confirm} onChange={e => setConfirm(e.target.value)}/>
              {msg && <div className="bc-pm-msg">{msg}</div>}
              <button className="bc-btn bc-btn--primary" type="submit"
                style={{width:"100%",height:38,fontSize:13}}>Update password</button>
            </form>
          )}
        </div>
      )}
    </div>
  );
}

/* ── Global search dropdown ── */
function GlobalSearch({ query, setQuery, navigate }) {
  const [focused, setFocused] = useState(false);
  const showTest = useShowTestData();  // respect the global LIVE/TEST toggle
  const { can } = usePermissions();
  const ref = useRef(null);

  useEffect(() => {
    function outside(e) { if (ref.current && !ref.current.contains(e.target)) setFocused(false); }
    document.addEventListener("mousedown", outside);
    return () => document.removeEventListener("mousedown", outside);
  }, []);

  const results = useMemo(() => {
    if (!query || query.length < 2) return null;
    const q = query.toLowerCase();
    const t = window.BC_testAccounts;
    // In LIVE mode, exclude test accounts + orphan orders from search too.
    // Never surface results from a screen this member can't open — search
    // is a side door into the same data, so it follows the same gate.
    const chefs = !canSeeScreen(can,"chefs") ? [] : (window.BC.chefs || [])
      .filter(c => showTest || !t || !t.isTestChef(c.docId))
      .filter(c => (c.name+c.area+c.id).toLowerCase().includes(q)).slice(0,4)
      .map(c => ({ type:"chef", label: c.name, sub: c.area+" · "+c.status, id:"chefs", docId:c.docId }));
    const orders = !canSeeScreen(can,"orders") ? [] : (window.BC.orders || [])
      .filter(o => !t || t.isOrderVisible(o, showTest))
      .filter(o => (o.id+o.chef+o.customer).toLowerCase().includes(q)).slice(0,4)
      .map(o => ({ type:"order", label: o.id+" · "+o.chef, sub: "EGP "+o.value+" · "+o.status, id:"orders", docId:o.docId }));
    const customers = !canSeeScreen(can,"customers") ? [] : (window.BC.customers || [])
      .filter(c => showTest || !t || !t.isTestCustomer(c.docId))
      .filter(c => (c.name+c.area).toLowerCase().includes(q)).slice(0,3)
      .map(c => ({ type:"customer", label: c.name, sub: c.area, id:"customers", docId:c.docId }));
    return [...chefs, ...orders, ...customers];
  }, [query, showTest, can]);

  const iconMap = { chef:"chefs", order:"orders", customer:"customers" };

  function pick(r) {
    // Remember which item to open, go to its page, then ask that page to
    // open the detail popup for it.
    window.BC._pendingDetail = { view: r.id, docId: r.docId };
    navigate(r.id);
    setFocused(false);
    setQuery("");
    setTimeout(() => window.dispatchEvent(new CustomEvent("bc-open-detail")), 120);
  }

  return (
    <div className="bc-search-wrap" ref={ref}>
      <label className="bc-search">
        <Icon name="search" size={18}/>
        <input value={query}
          onChange={e => setQuery(e.target.value)}
          onFocus={() => setFocused(true)}
          placeholder="Search chefs, orders, customers…"/>
        {query && <button className="bc-search-clear" onClick={() => setQuery("")}>
          <Icon name="x" size={14}/>
        </button>}
      </label>
      {focused && results && results.length > 0 && (
        <div className="bc-search-dropdown">
          {results.map((r,i) => (
            <button key={i} className="bc-search-result" onClick={() => pick(r)}>
              <span className="bc-search-ic"><Icon name={iconMap[r.type]} size={15}/></span>
              <span className="bc-search-label">{r.label}</span>
              <span className="bc-search-sub">{r.sub}</span>
            </button>
          ))}
        </div>
      )}
      {focused && results && results.length === 0 && query.length >= 2 && (
        <div className="bc-search-dropdown">
          <div className="bc-bell-empty">No results for "{query}"</div>
        </div>
      )}
    </div>
  );
}

/* ── Topbar ── */
function Topbar({ view, query, setQuery, navigate, onToggleSidebar }) {
  const user = firebase.auth().currentUser;
  const displayName = user?.displayName || user?.email?.split("@")[0] || "Founder";
  const firstName = displayName.split(" ")[0];
  const date = new Date().toLocaleDateString("en-GB", { weekday:"long", day:"numeric", month:"long" });
  const titles = {
    overview:  null, // handled separately
    chefs:     "Chef network",
    applications: "Applications",
    dishes:    "Dishes",
    orders:    "Live orders",
    customers: "Customers",
    ops:       "Operations",
    controls:  "Controls",
    notify:    "Notifications",
    crm:       "Outreach",
    settings:  "Team access",
  };

  return (
    <header className="bc-topbar">
      <div>
        {view === "overview" ? (
          <>
            <div className="bc-eyebrow">{date} · Cairo</div>
            <h1 className="bc-title-greeting">Hello {firstName} 👋</h1>
            <div className="bc-title-sub">Welcome back to BetyChef</div>
          </>
        ) : (
          <>
            <div className="bc-eyebrow">{date} · Cairo</div>
            <h1 className="bc-title">{titles[view] || "BetyChef"}</h1>
          </>
        )}
      </div>
      <div className="bc-top-actions">
        <TestDataToggle/>
        <GlobalSearch query={query} setQuery={setQuery} navigate={navigate}/>
        <ThemeToggle/>
        <ActivityBell/>
        <ProfileMenu/>
      </div>
    </header>
  );
}

/* ── Primitives ── */
function Pill({ status, sm }) {
  const map = {
    Active:"ok", Delivered:"ok", Connected:"ok", Sent:"ok",
    "On the way":"warn", Ready:"warn", Scheduled:"warn", Preparing:"info",
    New:"info", Joined:"muted", Paused:"muted", Cancelled:"bad",
  };
  return (
    <span className={"bc-pill bc-pill--"+(map[status]||"muted")+(sm?" bc-pill--sm":"")}>
      {status==="Cancelled" && <Icon name="x" size={11} stroke={2.6}/>}
      {status==="Active"    && <span className="bc-livedot"/>}
      {status}
    </span>
  );
}

function HealthBadge({ health }) {
  const cfg = {
    great:   { label:"Top chef", color:"#059212" },
    good:    { label:"Good",     color:"#10B981" },
    growing: { label:"Growing",  color:"#9BEC00" },
    inactive:{ label:"Inactive", color:"#C2410C" },
    new:     { label:"New",      color:"#67726B" },
  };
  const c = cfg[health] || cfg.new;
  return (
    <span className="bc-health-badge"
      style={{color:c.color,borderColor:c.color+"44",background:c.color+"11"}}>
      {c.label}
    </span>
  );
}

function Tag({ children }) { return <span className="bc-tag">{children}</span>; }

// Avatar: shows real photo if available, initials otherwise
function Avatar({ name, kind, size, photoUrl }) {
  const [imgErr, setImgErr] = useState(false);
  const initials = (name||"?").replace("Om ","").split(" ").map(s=>s[0]).filter(Boolean).slice(0,2).join("");
  const cls = "bc-avatar bc-avatar--"+(kind||"chef")+(size?" bc-avatar--"+size:"");

  // Only show image if it's a real URL (not a placeholder like "600 × 400")
  const isRealUrl = photoUrl &&
    photoUrl.startsWith("http") &&
    !photoUrl.includes("×") &&
    !photoUrl.match(/^\d+\s*[x×]\s*\d+$/i);

  if (isRealUrl && !imgErr) {
    return (
      <img src={photoUrl} alt={name} className={cls}
        style={{objectFit:"cover",flexShrink:0}}
        onError={() => setImgErr(true)}/>
    );
  }
  return <span className={cls}>{initials}</span>;
}

function Toggle({ on, onChange }) {
  return (
    <button className={"bc-toggle"+(on?" is-on":"")} onClick={() => onChange(!on)}
      role="switch" aria-checked={on}>
      <span className="bc-toggle-knob"/>
    </button>
  );
}

/* ── Pipeline ── */
function Pipeline({ stages }) {
  const max = Math.max(...stages.map(s=>s.n), 1);
  return (
    <div className="bc-pipeline">
      {stages.map(s => (
        <div className="bc-pipe-row" key={s.label}>
          <span className="bc-pipe-label">
            <span className="bc-pipe-dot" style={{background:s.color}}/>{s.label}
          </span>
          <div className="bc-pipe-track">
            <div className="bc-pipe-fill" style={{width:(s.n/max*100)+"%",background:s.color}}/>
          </div>
          <span className="bc-pipe-n">{s.n}</span>
        </div>
      ))}
    </div>
  );
}

/* ── Sparkline ── */
function Sparkline({ data, color }) {
  if (!data || data.length < 2) return null;
  const w=120,h=36,max=Math.max(...data),min=Math.min(...data);
  const pts = data.map((d,i)=>[i/(data.length-1)*w, h-((d-min)/(max-min||1))*(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} L 0 ${h} Z`;
  const id = "sp"+Math.abs(Math.round((data[0]||0)*1000+(data.length)*77));
  return (
    <svg className="bc-spark" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      <defs><linearGradient id={id} x1="0" x2="0" y1="0" y2="1">
        <stop offset="0" stopColor={color} stopOpacity="0.22"/>
        <stop offset="1" stopColor={color} stopOpacity="0"/>
      </linearGradient></defs>
      <path d={area} fill={`url(#${id})`}/>
      <path d={line} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

/* ── Stacked bars ── */
function StackedBars({ data }) {
  const max = Math.max(...data.map(d=>d.repeat+d.first), 1);
  return (
    <div className="bc-bars">
      {data.map(d => {
        const total = d.repeat+d.first;
        return (
          <div className="bc-bar-col" key={d.day}>
            <div className="bc-bar-total">{total||""}</div>
            <div className="bc-bar-stack" style={{height:(total/max*100)+"%"}}>
              <div className="bc-bar-seg" style={{flex:d.repeat||0,background:"var(--c-primary)"}}/>
              <div className="bc-bar-seg" style={{flex:d.first||0,background:"var(--c-saffron)"}}/>
            </div>
            <div className="bc-bar-label">{d.day}</div>
          </div>
        );
      })}
    </div>
  );
}

/* ── Area bars ── */
function AreaBars({ areas }) {
  const max = Math.max(...areas.map(a=>a.chefs), 1);
  return (
    <div className="bc-arealist">
      {areas.map(a => (
        <div className="bc-area-row" key={a.name}>
          <span className="bc-area-name"><Icon name="pin" size={13}/>{a.name}</span>
          <div className="bc-area-track"><div className="bc-area-fill" style={{width:(a.chefs/max*100)+"%"}}/></div>
          <span className="bc-area-n">{a.chefs}</span>
        </div>
      ))}
    </div>
  );
}

/* ── Modal ── */
function Modal({ open, onClose, children, title, wide }) {
  useEffect(() => {
    function esc(e) { if (e.key==="Escape") onClose(); }
    if (open) window.addEventListener("keydown", esc);
    return () => window.removeEventListener("keydown", esc);
  }, [open]);
  if (!open) return null;
  return (
    <div className="bc-modal-scrim" onClick={onClose}>
      <div className={"bc-modal"+(wide?" bc-modal--wide":"")} onClick={e=>e.stopPropagation()}>
        <div className="bc-modal-head">
          <h3>{title}</h3>
          <button className="bc-icon-btn" onClick={onClose}><Icon name="x" size={18}/></button>
        </div>
        <div className="bc-modal-body">{children}</div>
      </div>
    </div>
  );
}

/* ── Mobile nav ── */
function MobileNav({ view, setView }) {
  const ns = window.BC.northStar || {};
  const { can } = usePermissions();
  const [open, setOpen] = useState(false);

  const labels = {
    overview:"Home",orders:"Orders",chefs:"Chefs",applications:"Applications",dishes:"Dishes",customers:"Customers",
    ops:"Operations",notify:"Notifications",controls:"Controls",crm:"Outreach",settings:"Team Access",
  };

  // Only the sections this role can see
  const items = NAV.filter(n => !n.isSeparator && canSeeScreen(can, n.id));

  const activeLabel = labels[view] || "Menu";

  function pick(id) { setView(id); setOpen(false); }

  return (
    <>
      {/* Floating hamburger — bottom left, always there */}
      <button className="bc-fab" onClick={() => setOpen(o => !o)} aria-label="Menu">
        {open ? <Icon name="x" size={22} stroke={2.2}/> : (
          <span className="bc-fab-burger"><span/><span/><span/></span>
        )}
        {!open && (ns.pending||0) > 0 && <span className="bc-fab-badge">{ns.pending}</span>}
      </button>

      {/* Pop-up nav sheet */}
      {open && (
        <>
          <div className="bc-fab-scrim" onClick={() => setOpen(false)}/>
          <nav className="bc-fab-sheet">
            <div className="bc-fab-sheet-head">
              <span>Go to</span>
              <span className="bc-fab-current">{activeLabel}</span>
            </div>
            <div className="bc-fab-grid">
              {items.map(n => (
                <button key={n.id}
                  className={"bc-fab-item"+(view===n.id?" is-active":"")}
                  onClick={() => pick(n.id)}>
                  <span className="bc-fab-ic">
                    <Icon name={n.icon} size={22}/>
                    {n.id==="applications" && (ns.pending||0)>0 && <span className="bc-mnav-badge">{ns.pending}</span>}
                    {n.id==="orders" && <span className="bc-mnav-dot"/>}
                  </span>
                  <span className="bc-fab-label">{labels[n.id]}</span>
                </button>
              ))}
            </div>
          </nav>
        </>
      )}
    </>
  );
}

Object.assign(window, {
  Icon, NAV, NAV_GROUPS, Sidebar, Topbar, ProfileMenu, ActivityBell, GlobalSearch, MobileNav,
  useShowTestData, TestDataToggle, usePermissions, NAV_PERMISSION, TeamPreviewBar, Gate, canSeeScreen,
  Pill, HealthBadge, Tag, Avatar, Toggle, SideGoalRing,
  Pipeline, Sparkline, StackedBars, AreaBars, Modal,
});
