// ---------- Shell: Sidebar + Topbar + Command palette ----------
const AppCtx = React.createContext({});

function matchesClientWorkspaceLog(log, client, session) {
  if (!log || !client) return false;
  const normalizedClientName = String(client.name || "").trim().toLowerCase();
  const normalizedCompany = String(client.company || "").trim().toLowerCase();
  const normalizedSessionCompany = String(session?.companyName || session?.organizationKey || "").trim().toLowerCase();

  return (
    (log.customerId && log.customerId === client.id) ||
    (normalizedClientName && String(log.clientName || log.customerName || "").trim().toLowerCase() === normalizedClientName) ||
    (normalizedCompany && String(log.organizationName || log.company || "").trim().toLowerCase() === normalizedCompany) ||
    (normalizedSessionCompany && String(log.organizationName || log.company || "").trim().toLowerCase() === normalizedSessionCompany)
  );
}

const Sidebar = ({
  active,
  onNavigate,
  assistants = [],
  clients = [],
  callLogs = [],
  session,
  allowedViews,
  navOpen,
  onCloseNav,
  workspaceName,
}) => {
  const safeClients = Array.isArray(clients) ? clients.filter((client) => client && typeof client === "object") : [];
  const badgeCounts = { assistants: assistants.length || null, clients: safeClients.length || null };
  const isClient = session?.role === "client";
  const headerName = isClient ? (session?.companyName || session?.name || "Client workspace") : (workspaceName || "Developer workspace");
  const visibleItems = NAV.flatMap((group) =>
    group.items.filter((item) => isClient ? (item.clientAllowed && allowedViews?.has(item.id)) : true)
  );
  const grossProfit = React.useMemo(
    () => (Array.isArray(callLogs) ? callLogs.reduce((sum, log) => sum + Number(log?.breakdown?.grossProfit || 0), 0) : 0),
    [callLogs]
  );
  const clientWalletBalance = React.useMemo(() => {
    if (!isClient) return null;
    const matchedClient = safeClients.find((client) =>
      client?.id === session?.clientId ||
      String(client?.email || "").trim().toLowerCase() === String(session?.email || "").trim().toLowerCase() ||
      String(client?.name || "").trim().toLowerCase() === String(session?.name || "").trim().toLowerCase()
    );
    if (!matchedClient) return null;

    const matchingLogs = (Array.isArray(callLogs) ? callLogs : []).filter((log) =>
      matchesClientWorkspaceLog(log, matchedClient, session)
    );
    for (let i = matchingLogs.length - 1; i >= 0; i -= 1) {
      const balance = matchingLogs[i]?.balance;
      if (balance != null && balance !== "") return Number(balance);
    }
    return null;
  }, [isClient, safeClients, session, callLogs]);
  const footerLabel = isClient ? "Wallet balance" : "Gross profit";
  const footerAmount = isClient
    ? (clientWalletBalance != null ? fmtRM(clientWalletBalance) : "—")
    : fmtRM(grossProfit);
  const footerMeta = isClient
    ? (clientWalletBalance != null ? "Latest captured customer balance" : "No wallet balance captured yet")
    : `${safeClients.length} total client${safeClients.length === 1 ? "" : "s"} in scope`;
  const footerBarWidth = isClient
    ? (clientWalletBalance != null ? Math.min(100, Math.max(22, Math.abs(clientWalletBalance) / 50)) : 22)
    : Math.min(100, Math.max(22, safeClients.length * 14));

  return (
    <>
      <div className={`sb-backdrop ${navOpen ? "open" : ""}`} onClick={onCloseNav} />
      <aside className={`sb ${navOpen ? "open" : ""}`}>
        <div className="sb-brand">
          <img src="/assets/xandrix-voxpro-wide.svg" alt="Xandrix VoxPro" style={{ height: 44, objectFit: "contain", objectPosition: "left", flex: 1, minWidth: 0 }} />
          <button className="sb-close" onClick={onCloseNav} aria-label="Close navigation">
            <Icon name="x" />
          </button>
        </div>

        <div className="sb-ws">
          <div className="sb-ws-avatar">{headerName.slice(0, 1).toUpperCase()}</div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div className="sb-ws-name truncate">{headerName}</div>
            <div className="sb-ws-meta truncate">{isClient ? "Client workspace" : "Developer workspace"}</div>
          </div>
          <Badge tone={isClient ? "info" : "accent"}>{isClient ? "Client" : "Dev"}</Badge>
        </div>

        <div className="sb-search" onClick={() => window.__openCP && window.__openCP()}>
          <Icon name="search" />
          <span>Jump to anything</span>
          <kbd>Ctrl K</kbd>
        </div>

        <div className="sb-focus-card">
          <div className="sb-focus-label">Workspace focus</div>
          <div className="sb-focus-title">{isClient ? "Operate clearly" : "Build and operate"}</div>
          <div className="sb-focus-copy">
            {isClient
              ? "Launch campaigns, review calls, and read reporting without developer-only clutter."
              : "Move between assistant design, client setup, and live telephony with more context."}
          </div>
        </div>

        <div className="sb-nav">
          {NAV.map((group) => {
            const visItems = group.items.filter((item) =>
              isClient ? (item.clientAllowed && allowedViews?.has(item.id)) : true
            );
            if (visItems.length === 0) return null;
            return (
              <div className="sb-section" key={group.label}>
                <div className="sb-section-label">{group.label}</div>
                {visItems.map((item) => {
                  const badge = badgeCounts[item.id] || item.badge;
                  return (
                    <div
                      key={item.id}
                      className={`sb-item ${item.devOnly ? "dev-only" : ""} ${active === item.id ? "active" : ""}`}
                      onClick={() => onNavigate(item.id)}
                    >
                      <Icon name={item.icon} className="sb-item-icon" />
                      <span>{item.label}</span>
                      {item.dot && <span className="sb-item-dot" />}
                      {!item.dot && badge && <span className="sb-item-badge">{badge}</span>}
                    </div>
                  );
                })}
              </div>
            );
          })}
        </div>

        <div className="sb-foot">
          <div className="sb-foot-card">
            <div className="sb-foot-label">{footerLabel}</div>
            <div className="sb-foot-amount">{footerAmount}</div>
            <div className="sb-foot-meta">{footerMeta}</div>
            <div className="sb-foot-bar">
              <span style={{ width: `${footerBarWidth}%` }} />
            </div>
          </div>
        </div>
      </aside>
    </>
  );
};

const Topbar = ({
  crumbs,
  mode,
  setMode,
  theme,
  setTheme,
  onOpenCP,
  onOpenNav,
  session,
  workspaceName,
  viewLabel,
  viewSummary,
  focusPills = [],
}) => {
  const isAdmin = session?.role === "admin";
  const initials = session
    ? session.name.split(" ").map((word) => word[0] || "").join("").slice(0, 2).toUpperCase() || "??"
    : "??";

  const [profileOpen, setProfileOpen] = React.useState(false);
  const [showChangePw, setShowChangePw] = React.useState(false);
  const [pwForm, setPwForm] = React.useState({ email: "", current: "", next: "", confirm: "" });
  const [pwErr, setPwErr] = React.useState("");
  const [pwOk, setPwOk] = React.useState(false);
  const [pwSaving, setPwSaving] = React.useState(false);
  const menuRef = React.useRef(null);

  React.useEffect(() => {
    if (!profileOpen) return;
    function onOutside(event) {
      if (menuRef.current && !menuRef.current.contains(event.target)) setProfileOpen(false);
    }
    document.addEventListener("mousedown", onOutside);
    return () => document.removeEventListener("mousedown", onOutside);
  }, [profileOpen]);

  function handleLogout() {
    clearSession();
    window.location.href = "/login.html";
  }

  function openChangePw() {
    setPwForm({ email: session?.email || "", current: "", next: "", confirm: "" });
    setPwErr("");
    setPwOk(false);
    setProfileOpen(false);
    setShowChangePw(true);
  }

  async function submitChangePw() {
    setPwErr("");
    setPwOk(false);
    if (!pwForm.email || !pwForm.current || !pwForm.next) {
      setPwErr("All fields are required.");
      return;
    }
    if (pwForm.next !== pwForm.confirm) {
      setPwErr("New passwords do not match.");
      return;
    }
    if (pwForm.next.length < 8) {
      setPwErr("New password must be at least 8 characters.");
      return;
    }
    setPwSaving(true);
    try {
      await voxApi("/auth/change-password", {
        method: "POST",
        body: JSON.stringify({
          email: pwForm.email,
          currentPassword: pwForm.current,
          newPassword: pwForm.next,
        }),
      });
      setPwOk(true);
      setTimeout(() => setShowChangePw(false), 1500);
    } catch (error) {
      setPwErr(error.message);
    } finally {
      setPwSaving(false);
    }
  }

  return (
    <>
      <header className="tb">
        <button className="tb-nav-btn" onClick={onOpenNav} aria-label="Open navigation">
          <Icon name="more" />
        </button>

        <div className="tb-crumb">
          {crumbs.map((crumb, index) => (
            <React.Fragment key={index}>
              {index > 0 && <span className="tb-crumb-sep">/</span>}
              <span className={index === crumbs.length - 1 ? "tb-crumb-current" : ""}>{crumb}</span>
            </React.Fragment>
          ))}
        </div>

        <div className="tb-tools">
          {isAdmin && (
            <div className="mode-toggle">
              <button className={mode === "dev" ? "active" : ""} onClick={() => setMode("dev")}>Developer</button>
              <button className={mode === "client" ? "active" : ""} onClick={() => setMode("client")}>Client</button>
            </div>
          )}

          <button
            className="tb-icon-btn"
            onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
            title={theme === "dark" ? "Switch to light mode" : "Switch to dark mode"}
          >
            <Icon name={theme === "dark" ? "sun" : "moon"} />
          </button>

          <button className="tb-icon-btn" onClick={onOpenCP} title="Command palette">
            <Icon name="cmd" />
          </button>
          <a
            href="/docs.html"
            target="_blank"
            rel="noopener noreferrer"
            className="tb-icon-btn"
            title="Developer docs"
            style={{ display: "flex", alignItems: "center", justifyContent: "center", textDecoration: "none" }}
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
              <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/>
              <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>
              <line x1="9" y1="7" x2="15" y2="7"/>
              <line x1="9" y1="11" x2="15" y2="11"/>
              <line x1="9" y1="15" x2="12" y2="15"/>
            </svg>
          </a>
          <button className="tb-icon-btn" title="Notifications">
            <Icon name="bell" />
            <span className="dot" />
          </button>
          <div style={{ width: 1, height: 22, background: "var(--c-line)", margin: "0 4px" }} />

          <div className="tb-profile" ref={menuRef}>
            <div className="tb-avatar" onClick={() => setProfileOpen((open) => !open)}>{initials}</div>
            {profileOpen && (
              <div className="tb-profile-menu">
                <div className="tb-profile-head">
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{session?.name || "User"}</div>
                  <div style={{ fontSize: 11, color: "var(--c-text-3)", marginTop: 2 }}>{workspaceName || "Workspace"}</div>
                </div>
                <div className="tb-profile-item" onClick={openChangePw}>
                  <Icon name="settings" style={{ width: 13, height: 13 }} />
                  <span>Change password</span>
                </div>
                <div style={{ height: 1, background: "var(--c-line)", margin: "4px 0" }} />
                <div className="tb-profile-item" style={{ color: "var(--err)" }} onClick={handleLogout}>
                  <Icon name="logout" style={{ width: 13, height: 13 }} />
                  <span>Sign out</span>
                </div>
              </div>
            )}
          </div>
        </div>
      </header>

      <div className="hero-strip">
        <div className="hero-copy">
          <div className="hero-eyebrow">{workspaceName || "Workspace"} · {isAdmin ? "Developer mode" : "Client mode"}</div>
          <div className="hero-title">{viewLabel}</div>
          <div className="hero-summary">{viewSummary}</div>
        </div>
        <div className="hero-pills">
          {focusPills.map((pill) => (
            <span key={pill} className="hero-pill">{pill}</span>
          ))}
        </div>
      </div>

      {showChangePw && (
        <div className="modal-back" onClick={() => setShowChangePw(false)}>
          <div className="modal" onClick={(event) => event.stopPropagation()}>
            <div className="modal-head">
              <div className="card-title">Change password</div>
              <button className="tb-icon-btn" onClick={() => setShowChangePw(false)}>
                <Icon name="x" />
              </button>
            </div>
            <div className="modal-body">
              {pwOk ? (
                <div style={{ textAlign: "center", padding: "20px 0", color: "var(--ok)", fontSize: 14 }}>
                  Password changed successfully.
                </div>
              ) : (
                <>
                  <Field label="Your email">
                    <Input type="email" value={pwForm.email} onChange={(event) => setPwForm((form) => ({ ...form, email: event.target.value }))} placeholder="admin@example.com" />
                  </Field>
                  <Field label="Current password">
                    <Input type="password" value={pwForm.current} onChange={(event) => setPwForm((form) => ({ ...form, current: event.target.value }))} />
                  </Field>
                  <Field label="New password">
                    <Input type="password" value={pwForm.next} onChange={(event) => setPwForm((form) => ({ ...form, next: event.target.value }))} placeholder="Minimum 8 characters" />
                  </Field>
                  <Field label="Confirm new password">
                    <Input type="password" value={pwForm.confirm} onChange={(event) => setPwForm((form) => ({ ...form, confirm: event.target.value }))} />
                  </Field>
                  {pwErr && (
                    <div style={{ marginTop: 8, padding: "8px 12px", background: "rgba(239,68,68,.1)", border: "1px solid rgba(239,68,68,.25)", borderRadius: 7, color: "#f87171", fontSize: 12 }}>
                      {pwErr}
                    </div>
                  )}
                </>
              )}
            </div>
            {!pwOk && (
              <div className="modal-foot">
                <button className="btn btn-ghost" onClick={() => setShowChangePw(false)}>Cancel</button>
                <button className="btn btn-primary" onClick={submitChangePw} disabled={pwSaving}>
                  {pwSaving ? "Saving..." : "Change password"}
                </button>
              </div>
            )}
          </div>
        </div>
      )}
    </>
  );
};

const CommandPalette = ({ open, onClose, onNavigate }) => {
  const [q, setQ] = React.useState("");
  const [activeIndex, setActiveIndex] = React.useState(0);
  const inputRef = React.useRef(null);

  const items = React.useMemo(() => ([
    { group: "Navigate", id: "dashboard", label: "Go to Dashboard", icon: "home", action: () => onNavigate("dashboard") },
    { group: "Navigate", id: "assistants", label: "Go to Assistants", icon: "bot", action: () => onNavigate("assistants") },
    { group: "Navigate", id: "calls", label: "Go to Telephony", icon: "phone", action: () => onNavigate("calls") },
    { group: "Navigate", id: "logs", label: "Go to Call Logs", icon: "log", action: () => onNavigate("logs") },
    { group: "Navigate", id: "analytics", label: "Go to Analytics", icon: "chart", action: () => onNavigate("analytics") },
    { group: "Navigate", id: "clients", label: "Go to Clients", icon: "users", action: () => onNavigate("clients") },
    { group: "Actions", id: "new-assist", label: "Open Assistant Builder", icon: "plus", kbd: "Ctrl N", action: () => onNavigate("assistants") },
    { group: "Actions", id: "new-camp", label: "Open Blast Campaigns", icon: "send", action: () => onNavigate("blast") },
    { group: "Workspace", id: "billing", label: "Open Billing", icon: "wallet", action: () => onNavigate("billing") },
    { group: "Workspace", id: "settings", label: "Workspace settings", icon: "settings", action: () => onNavigate("system") },
  ].filter((item) => !q || item.label.toLowerCase().includes(q.toLowerCase()))), [onNavigate, q]);

  const groups = React.useMemo(() => items.reduce((acc, item) => {
    acc[item.group] = acc[item.group] || [];
    acc[item.group].push(item);
    return acc;
  }, {}), [items]);

  const flatItems = React.useMemo(() => Object.values(groups).flat(), [groups]);

  React.useEffect(() => {
    if (open && inputRef.current) {
      setQ("");
      setActiveIndex(0);
      setTimeout(() => inputRef.current && inputRef.current.focus(), 30);
    }
  }, [open]);

  React.useEffect(() => {
    if (activeIndex >= flatItems.length) setActiveIndex(0);
  }, [activeIndex, flatItems.length]);

  React.useEffect(() => {
    function onKeyDown(event) {
      if (!open) return;
      if (event.key === "ArrowDown") {
        event.preventDefault();
        setActiveIndex((index) => flatItems.length ? (index + 1) % flatItems.length : 0);
      } else if (event.key === "ArrowUp") {
        event.preventDefault();
        setActiveIndex((index) => flatItems.length ? (index - 1 + flatItems.length) % flatItems.length : 0);
      } else if (event.key === "Enter" && flatItems[activeIndex]) {
        event.preventDefault();
        flatItems[activeIndex].action && flatItems[activeIndex].action();
        onClose();
      }
    }
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [open, flatItems, activeIndex, onClose]);

  if (!open) return null;

  return (
    <div className="cp-back" onClick={onClose}>
      <div className="cp" onClick={(event) => event.stopPropagation()}>
        <div className="cp-search">
          <Icon name="search" />
          <input ref={inputRef} placeholder="Type a command or destination" value={q} onChange={(event) => setQ(event.target.value)} />
          <kbd className="kbd">ESC</kbd>
        </div>
        <div className="cp-list">
          {Object.entries(groups).map(([group, list]) => (
            <div key={group}>
              <div className="cp-group">{group}</div>
              {list.map((item) => (
                <div
                  key={item.id}
                  className={`cp-item ${flatItems[activeIndex]?.id === item.id ? "active" : ""}`}
                  onMouseEnter={() => setActiveIndex(flatItems.findIndex((candidate) => candidate.id === item.id))}
                  onClick={() => {
                    item.action && item.action();
                    onClose();
                  }}
                >
                  <Icon name={item.icon} />
                  <span>{item.label}</span>
                  {item.kbd && <span className="cp-item-kbd">{item.kbd}</span>}
                </div>
              ))}
            </div>
          ))}
          {items.length === 0 && <div className="empty-state">No results for "{q}"</div>}
        </div>
        <div className="cp-foot">
          <span><kbd>UP DOWN</kbd> move</span>
          <span><kbd>ENTER</kbd> open</span>
          <span><kbd>ESC</kbd> close</span>
          <span style={{ marginLeft: "auto" }}>VoxPro Console</span>
        </div>
      </div>
    </div>
  );
};

window.AppCtx = AppCtx;
window.Sidebar = Sidebar;
window.Topbar = Topbar;
window.CommandPalette = CommandPalette;
