// CommandPalette.jsx — global dashboard search and deep-link launcher
(function () {
  const { useState, useEffect } = React;
  const h = React.createElement;
  const NAV = window.NAV;
  const { fallbackCompanyUsers } = window.EmplixHashRouter;

  function CommandPalette({ ctx, setActive, onClose }) {
    const [q, setQ] = useState("");
    const [activeIndex, setActiveIndex] = useState(0);
    const items = [];
    const office = (ctx && ctx.office) || window.OFFICE || {};
    const DD = window.deriveDashboardData(office);
    const joinSearch = (...parts) => parts.flat(Infinity).filter(Boolean).join(" ");
		    const roleName = (rid) => {
		      const r = office.roleById && office.roleById[rid];
		      return r && window.officeRoleName ? window.officeRoleName(r, rid) : ((r && (r.short || r.title)) || rid || "");
		    };
	    const displayTime = (value) => window.officeTimeDisplay ? window.officeTimeDisplay(value) : value;
	    const displayAction = (value) => window.officeActionDisplay ? window.officeActionDisplay(value) : value;
	    const displaySource = (value) => window.officeSourceDisplay ? window.officeSourceDisplay(value) : value;
	    const failedCaseRoleId = (item) => {
	      if (item && item.roleId && office.roleById && office.roleById[item.roleId]) return item.roleId;
	      const text = [item && item.set, item && item.input, item && item.expected, item && item.got, item && item.future].join(" ").toLowerCase();
	      if (/customer|support|refund|warranty|damaged|kb|knowledge/.test(text) && office.roleById && office.roleById.cs) return "cs";
	      if (/proposal|quote|price|delivery|sales/.test(text) && office.roleById && office.roleById.sales) return "sales";
	      if (/brand|tone|social|community|post/.test(text) && office.roleById && office.roleById.social) return "social";
	      if (/invoice|receipt|bank|finance|account/.test(text) && office.roleById && office.roleById.acct) return "acct";
	      return office.roleById && office.roleById.clerk ? "clerk" : (((office.roles || []).find((r) => r.hired) || (office.roles || [])[0] || {}).id || "clerk");
	    };
    const folderName = (folderId) => (office.folders || []).find((fo) => fo.id === folderId)?.name || folderId || "Unfiled";
    const connectorStatus = (c) => c && c.status === "已連接" ? "Connected" : (c && c.status === "未連接" ? "Not connected" : ((c && c.status) || ""));
    const taskStageLabel = (stage) => ({ Intake: "New", Planning: "Plan", Running: "In progress", QA: "Check", Done: "Done" })[stage] || stage;
    const healthId = (s, i) => window.healthSystemId ? window.healthSystemId(s, i) : String((s && (s.connectorId || s.system)) || ("system-" + (i + 1))).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
    const settingsSections = [
      { id: "workspace", label: "Workspace settings", sub: "Client, environment and region", icon: "settings", search: "workspace client environment region" },
      { id: "governance", label: "Approval defaults", sub: "Approval, rules and repeat-work defaults", icon: "shield", search: "approval rules repeat work auto-run default" },
      { id: "notifications", label: "Notification settings", sub: "Approvals, value email and escalation alerts", icon: "bell", search: "notifications approval weekly value email alerts escalation" },
      { id: "access", label: "Team access levels", sub: "Users, roles and permission previews", icon: "users", search: "team access users roles permissions levels" },
    ];
    const openPage = (page, id) => ctx && ctx.openPage ? ctx.openPage(page, id) : setActive(page);
    const pushItem = (it) => items.push(Object.assign({ id: it.type + ":" + items.length, icon: "search" }, it));

    NAV.filter((n) => !n.hidden).forEach((n) => pushItem({
      id: "screen:" + n.id, type: "Page", label: n.label, icon: n.icon,
	      search: joinSearch(n.id, n.label, n.icon),
	      go: () => openPage(n.id),
	    }));
    (office.connectors || []).forEach((c) => {
      const label = (window.CONN_NAME_EN && window.CONN_NAME_EN[c.id]) || c.name || c.id;
      pushItem({
        id: "connector:" + c.id, type: "App", label, sub: [connectorStatus(c), c.owner, c.mode, c.health].filter(Boolean).join(" · "), icon: "mail",
        search: joinSearch(c.id, label, c.name, c.detail, c.owner, c.mode, connectorStatus(c), c.status, c.health, c.healthNote, c.note, c.stat, c.last, c.syncLog),
        go: () => openPage("connector", c.id),
      });
    });
    (DD.expansion || []).forEach((p) => pushItem({
      id: "roi:" + p.id, type: "Value estimate", label: p.name, sub: [p.lift, p.conf ? p.conf + " confidence" : null, p.note].filter(Boolean).join(" · "), icon: "trending",
      search: joinSearch(p.id, p.name, p.lift, p.conf, p.note, p.area, p.category),
      go: () => openPage("roi", p.id),
    }));
    (((office.ops || {}).health) || []).forEach((s, i) => {
      const sid = healthId(s, i);
      pushItem({
	        id: "health:" + sid, type: "App status", label: displaySource(s.system || sid), sub: [s.status, displaySource(s.detail), displayTime(s.since)].filter(Boolean).join(" · "), icon: "server",
        search: joinSearch(sid, s.id, s.connectorId, s.system, s.status, s.detail, s.since),
        go: () => openPage("health", sid),
      });
    });
    settingsSections.forEach((s) => pushItem({
      id: "settings:" + s.id, type: "Settings", label: s.label, sub: s.sub, icon: s.icon,
      search: joinSearch(s.id, s.label, s.sub, s.search),
      go: () => openPage("settings", s.id),
    }));
	    DD.employees.forEach((e) => pushItem({
      id: "employee:" + e.id, type: "Employee", label: e.short, sub: e.dept, icon: "users",
      search: joinSearch(e.id, e.short, e.name, e.dept, e.owner, e.status, e.lastTask),
      go: () => openPage("employee", e.id),
    }));
    const skillWorkOrderRows = Object.keys(office.workOrders || {}).flatMap((col) => ((office.workOrders || {})[col] || []).map((wo) => Object.assign({ col }, wo)));
    function latestPaletteSkillWorkOrder(skillId) {
      const rows = skillWorkOrderRows.filter((wo) => wo.workflow && wo.workflow.skillId === skillId && !wo.workflow.cancelled && wo.workflow.approvalStatus !== "approved");
      rows.sort((a, b) => parseInt(String(b.id || "").replace("WO-", ""), 10) - parseInt(String(a.id || "").replace("WO-", ""), 10));
      return rows[0] || null;
    }
    function recordPaletteAgentLaunch(skill, wo) {
      try {
        sessionStorage.setItem("emplix-agent-launch-intent", JSON.stringify({
          source: "command-palette",
          skillId: skill.id,
          skillTitle: skill.title,
          area: skill.area,
          areaSlug: skill.areaSlug,
          status: wo ? (wo.col || "Running") : "Ready",
          workOrderId: wo ? wo.id : "",
          stepCount: (skill.steps || []).length,
          at: Date.now(),
        }));
      } catch (e) { /* best effort launch receipt */ }
    }
    (window.SCENARIO_SKILLS || []).forEach((s) => {
      const latestWo = latestPaletteSkillWorkOrder(s.id);
      pushItem({
        id: "skill:" + s.id, type: "Task template", label: s.title, sub: s.area + " · " + (s.stage || []).join(" + "), icon: "graduation",
        search: joinSearch(s.id, s.title, s.area, s.category, s.owner, s.level, s.stage, s.tasks, s.outcomes),
        go: () => openPage("training", s.id),
      });
      pushItem({
        id: "agent:" + s.id,
        type: "Employee",
        label: (latestWo ? "Continue with employee: " : "Start with employee: ") + s.title,
        sub: latestWo ? [latestWo.id, taskStageLabel(latestWo.col), s.area].filter(Boolean).join(" · ") : s.area + " · approval required",
        icon: "message",
        search: joinSearch("agent chat", "start agent", "continue agent", "run skill", s.id, s.title, s.area, s.stage, s.tasks, s.outcomes, latestWo && latestWo.id),
        go: () => {
          recordPaletteAgentLaunch(s, latestWo);
          openPage("agent", s.id + (latestWo ? "~" + latestWo.id : ""));
        },
      });
    });
    (office.inbox || []).forEach((item) => pushItem({
      id: "approval:" + item.id, type: "Approval", label: item.title,
      sub: [item.id, item.workOrderId, roleName(item.role), item.skill].filter(Boolean).join(" · "),
      icon: "stamp",
      search: joinSearch(item.id, item.workOrderId, item.title, item.role, roleName(item.role), item.skill, item.risk, item.riskNote, item.source, item.sourceSnippet, item.lines),
      go: () => { if (ctx && ctx.setHighlight) ctx.setHighlight(item.id); openPage("approvals"); },
    }));
    const board = office.workOrders || {};
	    Object.keys(board).forEach((col) => (board[col] || []).forEach((w) => pushItem({
	      id: "workorder:" + w.id, type: "Task", label: w.title, sub: w.id + " · " + taskStageLabel(col), icon: "clipboard",
	      search: joinSearch(w.id, w.title, col, w.emp, roleName(w.emp), w.sla, w.sources, w.step, w.risk, w.future),
	      go: () => openPage("workorder", w.id),
	    })));
	    (office.failedCases || []).forEach((f) => {
	      const rid = failedCaseRoleId(f);
	      pushItem({
	        id: "failed-case:" + f.id,
	        type: "Task check",
	        label: (f.id || "Case") + " · " + (f.set || "Check issue"),
	        sub: [f.sev || "Check", f.qaReviewedAt ? "Reviewed" : "Needs review", f.qaFixWorkOrderId, roleName(rid)].filter(Boolean).join(" · "),
	        icon: "alert",
	        search: joinSearch("check issue training quality", f.id, f.set, f.input, f.expected, f.got, f.sev, f.future, f.roleId, roleName(rid), f.qaReviewedAt, f.qaReviewedBy, f.qaFixWorkOrderId),
	        go: () => { if (ctx && ctx.setHighlight) ctx.setHighlight(f.id); openPage("training-setup", "quality/" + rid); },
	      });
	    });
	    (office.files || []).forEach((f) => pushItem({
      id: "file:" + f.id, type: "File", label: f.name,
	      sub: [f.kind, folderName(f.folder), (f.tags || []).join(", ")].filter(Boolean).join(" · "),
	      icon: "file",
	      search: joinSearch(f.id, f.name, f.kind, f.folder, folderName(f.folder), f.tags, f.source, f.usedBy, f.citedBy),
	      go: () => { if (ctx && ctx.setHighlight) ctx.setHighlight(f.id); openPage("files", f.id); },
	    }));
    (office.folders || []).forEach((fo) => pushItem({
      id: "folder:" + fo.id, type: "Folder", label: fo.name,
      sub: fo.parent ? "Folder · " + folderName(fo.parent) : "Top-level folder",
      icon: "folder",
      search: joinSearch(fo.id, fo.name, fo.parent, folderName(fo.parent), fo.defaultForSource),
      go: () => openPage("files", "folder/" + encodeURIComponent(String(fo.id || ""))),
    }));
    (office.staging || []).forEach((st) => pushItem({
      id: "staging:" + st.id, type: "File to review",
      label: st.name || st.file || st.title || st.id,
      sub: [st.id, st.kind, "Files"].filter(Boolean).join(" · "),
      icon: "inbox",
      search: joinSearch(st.id, st.name, st.file, st.title, st.kind, st.from, st.source, st.suggestedName, st.suggestedFolder, st.targetFolder),
      go: () => { if (ctx && ctx.setHighlight) ctx.setHighlight(st.id); openPage("files", "smart/pending"); },
    }));
    const users = (office.companyUsers && office.companyUsers.length) ? office.companyUsers : fallbackCompanyUsers();
    users.forEach((u) => pushItem({
      id: "user:" + u.id, type: "Team member", label: u.name,
      sub: [u.email, u.department, u.level, u.status].filter(Boolean).join(" · "),
      icon: "users",
      search: joinSearch(u.id, u.name, u.email, u.department, u.level, u.status, u.onboarding, u.invitedBy),
      go: () => openPage("company"),
    }));
    (office.auditLog || []).forEach((a) => pushItem({
      id: "audit:" + a.id, type: "History", label: a.title || a.action || a.id,
	      sub: [a.id, displayAction(a.action), roleName(a.roleId), a.note].filter(Boolean).join(" · "),
      icon: "scroll",
      search: joinSearch(a.id, a.time, a.action, a.title, a.tool, a.rule, a.note, a.roleId, roleName(a.roleId), a.approver && a.approver.name, a.approver && a.approver.level),
      go: () => openPage("audit-event", a.id),
    }));
    ((office.ops || {}).incidents || []).forEach((inc) => pushItem({
      id: "incident:" + inc.id, type: "Issue", label: inc.title || inc.source || inc.id,
	      sub: [inc.id, inc.status, displaySource(inc.source)].filter(Boolean).join(" · "),
      icon: "alert",
      search: joinSearch(inc.id, inc.severity, inc.title, inc.source, inc.status, inc.opened, inc.detail),
      go: () => openPage("incident", inc.id),
    }));
    const ql = q.trim().toLowerCase();
    function matchScore(it) {
      const label = String(it.label || "").toLowerCase();
      const sub = String(it.sub || "").toLowerCase();
      const type = String(it.type || "").toLowerCase();
      const full = joinSearch(it.search, it.label, it.sub, it.type).toLowerCase();
      if (label === ql) return 0;
      if (label.startsWith(ql)) return 1;
      if (label.includes(ql)) return 2;
      if (sub.includes(ql)) return 3;
      if (type.includes(ql)) return 4;
      if (full.includes(ql)) return 5;
      return 99;
    }
    const filtered = ql
      ? items.map((it, i) => ({ it, i, score: matchScore(it) })).filter((row) => row.score < 99).sort((a, b) => a.score - b.score || a.i - b.i).slice(0, 9).map((row) => row.it)
      : items.slice(0, 8);
    const selectedIndex = filtered.length ? Math.min(activeIndex, filtered.length - 1) : -1;
    useEffect(() => { setActiveIndex(0); }, [q]);
    function runItem(it) {
      if (!it) return;
      it.go();
      onClose();
    }
    function onKeyDown(e) {
      if (e.key === "Escape") { e.preventDefault(); onClose(); return; }
      if (e.key === "ArrowDown") { e.preventDefault(); setActiveIndex((i) => filtered.length ? (i + 1) % filtered.length : 0); return; }
      if (e.key === "ArrowUp") { e.preventDefault(); setActiveIndex((i) => filtered.length ? (i - 1 + filtered.length) % filtered.length : 0); return; }
      if (e.key === "Enter") { e.preventDefault(); runItem(filtered[selectedIndex]); }
    }
    return h("div", { onClick: onClose, style: { position: "fixed", inset: 0, zIndex: 80, display: "flex", justifyContent: "center", paddingTop: "12vh",
      background: "rgba(20,28,45,0.4)", backdropFilter: "blur(3px)", animation: "fadeUp .15s" } },
      h("div", { onClick: (e) => e.stopPropagation(), className: "glass", role: "dialog", "aria-modal": "true", "aria-label": "Command palette", "data-command-palette": "true", style: { width: 560, maxWidth: "92vw", height: "fit-content", maxHeight: "70vh", display: "flex", flexDirection: "column", padding: 0, boxShadow: "var(--shadow-lg)", animation: "fadeUp .2s" } },
        h("div", { className: "row gap10", style: { padding: "14px 18px", borderBottom: "1px solid var(--border)" } },
          h(window.Icon, { name: "search", size: 18, color: "var(--text-faint)" }),
          h("input", { autoFocus: true, value: q, onChange: (e) => setQ(e.target.value), onKeyDown, role: "combobox", "aria-controls": "cmd-results", "aria-expanded": "true", "aria-activedescendant": selectedIndex >= 0 ? "cmd-opt-" + selectedIndex : undefined, "data-command-palette-input": "true", placeholder: "Search pages, apps, tasks and files...",
            style: { flex: 1, border: "none", outline: "none", background: "transparent", fontFamily: "var(--font)", fontSize: 15, color: "var(--text)" } }),
          h("span", { className: "mono", style: { fontSize: 11, color: "var(--text-faint)", border: "1px solid var(--border)", borderRadius: 6, padding: "2px 6px" } }, "ESC")),
        h("div", { id: "cmd-results", role: "listbox", "aria-label": "Command results", "data-command-palette-results": "true", "data-command-palette-result-count": String(filtered.length), style: { overflowY: "auto", padding: 8 } },
          filtered.length ? filtered.map((it, i) =>
            h("button", { key: it.id, id: "cmd-opt-" + i, role: "option", "aria-selected": i === selectedIndex, "data-command-palette-id": it.id, tabIndex: -1, onMouseEnter: () => setActiveIndex(i), onClick: () => runItem(it), className: "dd-opt" + (i === selectedIndex ? " active" : ""),
              style: { display: "flex", alignItems: "center", gap: 12, width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 9, border: "none", cursor: "pointer", fontFamily: "var(--font)", marginBottom: 2 } },
              h("div", { style: { width: 30, height: 30, borderRadius: 8, background: "var(--bg-3)", border: "1px solid var(--border)", display: "grid", placeItems: "center", color: "var(--text-dim)", flex: "none" } }, h(window.Icon, { name: it.icon, size: 15 })),
              h("div", { className: "grow", style: { minWidth: 0 } }, h("div", { style: { fontSize: 13.5, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" } }, it.label), it.sub && h("div", { style: { fontSize: 11.5, color: "var(--text-faint)" } }, String(it.sub).split(" · ").map((part, partIndex) => h(React.Fragment, { key: partIndex }, partIndex > 0 && h("span", null, " · "), h("span", null, part))))),
              h("span", { className: "badge badge-neutral", style: { fontSize: 10.5, flex: "none" } }, it.type))) :
            h(window.EmptyHint, { icon: "search", text: "No matches for “" + q + "”" }))));
  }

  window.CommandPalette = CommandPalette;
})();
