/* ===== shell.jsx — AppShell, Sidebar, TopBar, CmdK, MobileShell ===== */
(function () {
  const { Icon, Button, IconBtn, Input, Kbd, Avatar, AlarmChip, Badge, cls,
    useStore, navigate, useRoute } = window;

  /* ---------- Logo ---------- */
  function Logo({ size = 28, label = true }) {
    return (
      <div className="flex items-center gap-2 select-none">
        <div className="relative flex items-center justify-center" style={{ width: size, height: size }}>
          <div className="absolute inset-0 rounded-[8px] bg-ink-900"></div>
          <div className="absolute inset-[5px] rounded-[5px] ring-1 ring-white/15"></div>
          <span className="relative text-white font-bold text-[11px] tracking-tighter font-mono">FE</span>
        </div>
        {label && (
          <div className="leading-tight">
            <div className="text-[13px] font-semibold text-ink-900 tracking-tight">Firsteck Bio</div>
            <div className="text-[10px] text-ink-500 -mt-0.5 tracking-wider uppercase">Lab Inventory</div>
          </div>
        )}
      </div>
    );
  }

  /* ---------- Nav model ---------- */
  const NAV = [
    { kind: 'group', label: '总览' },
    { id: 'dash',     label: '仪表盘',      icon: Icon.home,     to: '/' },
    { id: 'alerts',   label: '全部报警',    icon: Icon.bell,     to: '/alerts', badgeKey: 'alerts' },
    { id: 'search',   label: '全局搜索',    icon: Icon.search,   to: null, action: 'cmdk', kbd: ['⌘','K'] },

    { kind: 'group', label: '模块 R · 试剂' },
    { id: 'r-prod',   label: '产品目录',    icon: Icon.tag,      to: '/reagents/products' },
    { id: 'r-batch',  label: '批次',        icon: Icon.flask,    to: '/reagents/batches' },
    { id: 'r-out',    label: '取货',        icon: Icon.arrowR,   to: '/reagents/outflow/new', accent: true },

    { kind: 'group', label: '模块 D · 设备' },
    { id: 'd-prod',   label: '设备型号',    icon: Icon.cpu,      to: '/devices/products' },
    { id: 'd-units',  label: '设备列表',    icon: Icon.box,      to: '/devices/units' },
    { id: 'd-trans',  label: '新转移',      icon: Icon.truck,    to: '/devices/transfer/new', accent: true },

    { kind: 'group', label: '主数据' },
    { id: 'sup',      label: '供货商',      icon: Icon.building, to: '/suppliers' },
    { id: 'cus',      label: '客户',        icon: Icon.users,    to: '/customers' },

    { kind: 'group', label: '系统' },
    { id: 'users',    label: '用户',        icon: Icon.user,     to: '/settings/users' },
    { id: 'thr',      label: '低库存阈值',  icon: Icon.settings, to: '/settings/thresholds' },
  ];

  /* ---------- Sidebar ---------- */
  function Sidebar({ collapsed, onCollapse }) {
    const { allAlarms, set } = useStore();
    const { hash } = useRoute();
    return (
      <aside className={cls(
        'shrink-0 h-full bg-white border-r border-ink-200 flex flex-col transition-all',
        collapsed ? 'w-[60px]' : 'w-[224px]'
      )}>
        <div className={cls('flex items-center h-14 px-3.5 border-b border-ink-100',
          collapsed ? 'justify-center' : 'justify-between')}>
          <Logo label={!collapsed} />
          {!collapsed && (
            <IconBtn icon={Icon.chevLeft} label="折叠" onClick={() => onCollapse(true)} />
          )}
        </div>

        <nav className="flex-1 overflow-y-auto px-2 py-3">
          {NAV.map((item, i) => {
            if (item.kind === 'group') {
              if (collapsed) return <div key={i} className="my-2 mx-2 h-px bg-ink-100"></div>;
              return (
                <div key={i} className="px-2 pt-3 pb-1 text-[10px] uppercase tracking-wider text-ink-400 font-medium">
                  {item.label}
                </div>
              );
            }
            const active = hash === item.to || (item.to !== '/' && item.to && hash.startsWith(item.to.split('/').slice(0, 3).join('/')));
            const exact = hash === item.to;
            const badge = item.badgeKey === 'alerts' ? allAlarms.length : null;
            return (
              <button key={item.id}
                onClick={() => {
                  if (item.action === 'cmdk') set({ cmdkOpen: true });
                  else if (item.to) navigate(item.to);
                }}
                className={cls(
                  'group relative w-full flex items-center gap-2.5 rounded-md px-2.5 h-9 my-0.5 text-sm transition-colors',
                  exact ? 'bg-ink-900 text-white font-medium'
                        : 'text-ink-700 hover:bg-ink-100 hover:text-ink-900'
                )}
                title={collapsed ? item.label : undefined}>
                <item.icon size={15} className="shrink-0" />
                {!collapsed && (
                  <>
                    <span className="flex-1 text-left truncate">{item.label}</span>
                    {item.accent && exact !== true && <span className="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>}
                    {badge != null && badge > 0 && (
                      <span className={cls(
                        'ml-auto min-w-[18px] h-[18px] px-1 rounded-full inline-flex items-center justify-center text-[10px] font-medium',
                        exact ? 'bg-white text-ink-900' : 'bg-red-600 text-white'
                      )}>{badge}</span>
                    )}
                    {item.kbd && (
                      <span className="flex gap-0.5">
                        {item.kbd.map((k) => <Kbd key={k}>{k}</Kbd>)}
                      </span>
                    )}
                  </>
                )}
              </button>
            );
          })}
        </nav>

        {collapsed ? (
          <div className="p-2 border-t border-ink-100 flex justify-center">
            <IconBtn icon={Icon.chevRight} label="展开" onClick={() => onCollapse(false)} />
          </div>
        ) : (
          <div className="p-3 border-t border-ink-100">
            <UserChip />
          </div>
        )}
      </aside>
    );
  }

  function UserChip() {
    const { users, currentUser, currentUserId, logout } = useStore();
    const u = currentUser || users.find((x) => x.id === currentUserId);
    if (!u) return null;
    const initials = (u.avatar || u.name || u.email || '?').slice(0, 2).toUpperCase();
    return (
      <div className="flex items-center gap-2.5">
        <Avatar name={initials} size={32} />
        <div className="flex-1 min-w-0 leading-tight">
          <div className="text-xs font-medium truncate">{u.name || u.email}</div>
          <div className="text-[10px] text-ink-500 truncate">{u.role || u.email}</div>
        </div>
        <IconBtn icon={Icon.x} label="退出登录" onClick={() => { if (confirm('确认退出登录？')) logout?.(); }} />
      </div>
    );
  }

  /* ---------- TopBar ---------- */
  function TopBar({ title, breadcrumbs, actions, onCollapseToggle }) {
    const { set, allAlarms } = useStore();
    return (
      <header className="h-14 shrink-0 bg-white/80 backdrop-blur border-b border-ink-200 px-4 flex items-center gap-3 sticky top-0 z-30">
        <div className="flex-1 min-w-0 flex items-center gap-3">
          {breadcrumbs && (
            <nav className="flex items-center gap-1.5 text-sm min-w-0 truncate">
              {breadcrumbs.map((b, i) => (
                <React.Fragment key={i}>
                  {i > 0 && <Icon.chevRight size={12} className="text-ink-300 shrink-0" />}
                  {b.to ? (
                    <button onClick={() => navigate(b.to)} className="text-ink-500 hover:text-ink-900 truncate">{b.label}</button>
                  ) : (
                    <span className="text-ink-900 font-medium truncate">{b.label}</span>
                  )}
                </React.Fragment>
              ))}
            </nav>
          )}
          {!breadcrumbs && title && (
            <h1 className="text-base font-semibold text-ink-900 tracking-tight truncate">{title}</h1>
          )}
        </div>

        {/* Search trigger */}
        <button onClick={() => set({ cmdkOpen: true })}
          className="hidden md:flex items-center gap-2 h-9 px-3 rounded-lg bg-ink-50 hover:bg-ink-100 text-ink-500 text-sm ring-1 ring-ink-100 transition-colors min-w-[280px]">
          <Icon.search size={14} />
          <span className="flex-1 text-left">搜产品 / 厂家 / SN / 批号…</span>
          <Kbd>⌘</Kbd><Kbd>K</Kbd>
        </button>

        <div className="hidden md:flex items-center gap-1.5">
          <button onClick={() => navigate('/alerts')}
            className="relative h-9 w-9 rounded-lg hover:bg-ink-100 inline-flex items-center justify-center text-ink-700">
            <Icon.bell size={16} />
            {allAlarms.length > 0 && (
              <span className="absolute -top-0.5 -right-0.5 min-w-[16px] h-4 px-1 rounded-full bg-red-600 text-white text-[10px] font-medium inline-flex items-center justify-center">
                {allAlarms.length}
              </span>
            )}
          </button>

        </div>

        {actions}
      </header>
    );
  }

  /* ---------- PageHeader (above content) ---------- */
  function PageHeader({ title, hint, actions, tabs, activeTab, onTab }) {
    return (
      <div className="px-6 pt-6 pb-3 border-b border-ink-100 bg-white">
        <div className="flex items-start justify-between gap-3 mb-3">
          <div>
            <h1 className="text-xl font-semibold tracking-tight text-ink-900">{title}</h1>
            {hint && <p className="text-sm text-ink-500 mt-1">{hint}</p>}
          </div>
          {actions && <div className="flex items-center gap-2">{actions}</div>}
        </div>
        {tabs && <window.Tabs tabs={tabs} active={activeTab} onChange={onTab} className="-mb-3" />}
      </div>
    );
  }

  /* ---------- Cmd+K palette ---------- */
  function CmdK() {
    const { cmdkOpen, set, search, allAlarms } = useStore();
    const [q, setQ] = React.useState('');
    const [hi, setHi] = React.useState(0);
    React.useEffect(() => {
      const on = (e) => {
        if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
          e.preventDefault();
          set({ cmdkOpen: true });
        }
        if (e.key === 'Escape') set({ cmdkOpen: false });
      };
      window.addEventListener('keydown', on);
      return () => window.removeEventListener('keydown', on);
    }, []);
    React.useEffect(() => { if (cmdkOpen) setQ(''); setHi(0); }, [cmdkOpen]);

    if (!cmdkOpen) return null;

    const results = q ? search(q) : [];
    const grouped = window.groupBy(results, (r) => r.kind);
    const groupLabels = {
      reagent_product: '🧪 试剂产品',
      reagent_batch:   '📦 试剂批次',
      device_product:  '🔬 设备型号',
      device_unit:     '🔧 设备 (SN)',
      supplier:        '🏭 供货商',
      customer:        '🏥 客户',
    };
    const groupOrder = ['reagent_product','reagent_batch','device_product','device_unit','supplier','customer'];

    const quickActions = [
      { id: 'q1', icon: Icon.arrowR, label: '取货 / 新出库', sub: '记录一条试剂取货', to: '/reagents/outflow/new' },
      { id: 'q2', icon: Icon.truck,  label: '新设备转移',   sub: '从 A → B 转移设备',  to: '/devices/transfer/new' },
      { id: 'q3', icon: Icon.plus,   label: '新建批次',     sub: '试剂入库',          to: '/reagents/batches/new' },
      { id: 'q4', icon: Icon.bell,   label: `查看 ${allAlarms.length} 个报警`, sub: '全部报警列表', to: '/alerts' },
    ];

    const flatItems = q
      ? results
      : quickActions;

    return (
      <div className="fixed inset-0 z-[150] flex items-start justify-center pt-[10vh] px-4 animate-fadein"
        onClick={() => set({ cmdkOpen: false })}>
        <div className="absolute inset-0 bg-ink-950/30 backdrop-blur-[2px]"></div>
        <div onClick={(e) => e.stopPropagation()}
          className="relative w-full max-w-2xl bg-white rounded-2xl shadow-pop ring-1 ring-ink-200 overflow-hidden animate-pop">
          <div className="flex items-center gap-3 px-4 h-14 border-b border-ink-100">
            <Icon.search size={18} className="text-ink-400" />
            <input autoFocus
              value={q} onChange={(e) => { setQ(e.target.value); setHi(0); }}
              placeholder="搜产品 / 厂家 / SN / 批号…"
              className="flex-1 text-[15px] bg-transparent focus:outline-none placeholder:text-ink-400" />
            <Kbd>ESC</Kbd>
          </div>

          <div className="max-h-[420px] overflow-y-auto py-2">
            {!q && (
              <>
                <div className="px-4 pt-2 pb-1.5 text-[10px] uppercase tracking-wider text-ink-400">快速操作</div>
                {quickActions.map((a) => (
                  <button key={a.id}
                    onClick={() => { set({ cmdkOpen: false }); navigate(a.to); }}
                    className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-ink-50 text-left">
                    <span className="h-8 w-8 rounded-md bg-ink-100 text-ink-700 inline-flex items-center justify-center">
                      <a.icon size={15} />
                    </span>
                    <span className="flex-1 min-w-0">
                      <span className="block text-sm text-ink-900">{a.label}</span>
                      <span className="block text-xs text-ink-500">{a.sub}</span>
                    </span>
                    <Icon.cornerR size={14} className="text-ink-300" />
                  </button>
                ))}
                <div className="px-4 pt-3 pb-1.5 text-[10px] uppercase tracking-wider text-ink-400">提示</div>
                <div className="px-4 py-2 text-xs text-ink-500 flex flex-wrap items-center gap-x-4 gap-y-1.5">
                  <span className="flex items-center gap-1"><Kbd>↑</Kbd><Kbd>↓</Kbd> 浏览</span>
                  <span className="flex items-center gap-1"><Kbd>↵</Kbd> 跳转</span>
                  <span className="flex items-center gap-1"><Kbd>⌘</Kbd><Kbd>K</Kbd> 打开</span>
                </div>
              </>
            )}

            {q && groupOrder.map((k) => {
              const items = grouped.get(k);
              if (!items) return null;
              return (
                <div key={k}>
                  <div className="px-4 pt-2 pb-1.5 text-[10px] uppercase tracking-wider text-ink-400">{groupLabels[k]}</div>
                  {items.map((it) => (
                    <button key={it.id}
                      onClick={() => { set({ cmdkOpen: false }); navigate(it.route); }}
                      className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-ink-50 text-left">
                      <span className="flex-1 min-w-0">
                        <span className="block text-sm text-ink-900 truncate">{it.title}</span>
                        <span className="block text-xs text-ink-500 truncate">{it.sub}</span>
                      </span>
                      <Icon.cornerR size={14} className="text-ink-300" />
                    </button>
                  ))}
                </div>
              );
            })}

            {q && results.length === 0 && (
              <div className="py-10 text-center">
                <div className="text-sm text-ink-500">未找到 "{q}"</div>
                <div className="text-xs text-ink-400 mt-1">尝试搜索产品名、SN、批号、厂家或客户名</div>
              </div>
            )}
          </div>

          <div className="px-4 h-9 border-t border-ink-100 bg-ink-50/60 flex items-center justify-between text-[11px] text-ink-500">
            <div className="flex items-center gap-1.5">
              <Icon.sparkle size={11} />
              主搜「产品名 + 厂家名」 · 结果按实体分组
            </div>
            <div className="flex items-center gap-3">
              <span className="flex items-center gap-1"><Kbd>⌘</Kbd><Kbd>↵</Kbd> 新标签</span>
            </div>
          </div>
        </div>
      </div>
    );
  }

  /* ---------- Mobile bottom nav ---------- */
  function MobileBottomNav() {
    const { hash } = useRoute();
    const { set, allAlarms } = useStore();
    const tabs = [
      { id: 'dash',  to: '/',           label: '仪表盘', icon: Icon.home },
      { id: 'al',    to: '/alerts',     label: '报警',   icon: Icon.bell, badge: allAlarms.length },
      { id: 'plus',  to: null,           label: '',       icon: Icon.plus, primary: true, action: 'plus' },
      { id: 'rb',    to: '/reagents/batches', label: '试剂', icon: Icon.flask },
      { id: 'du',    to: '/devices/units',    label: '设备', icon: Icon.cpu },
    ];
    return (
      <div className="absolute bottom-0 left-0 right-0 bg-white border-t border-ink-200 px-2 pt-1.5 pb-3 z-30">
        <div className="flex items-end justify-around">
          {tabs.map((t) => {
            const active = t.to && (hash === t.to || (t.to !== '/' && hash.startsWith(t.to)));
            if (t.primary) {
              return (
                <button key={t.id} onClick={() => set({ cmdkOpen: true })}
                  className="-mt-5 h-12 w-12 rounded-2xl bg-ink-900 text-white shadow-pop flex items-center justify-center">
                  <t.icon size={20} />
                </button>
              );
            }
            return (
              <button key={t.id} onClick={() => t.to && navigate(t.to)}
                className={cls('flex flex-col items-center gap-0.5 px-2 py-1 rounded-lg relative',
                  active ? 'text-ink-900' : 'text-ink-400')}>
                <t.icon size={18} />
                <span className="text-[9px] font-medium">{t.label}</span>
                {t.badge > 0 && (
                  <span className="absolute top-0 right-1 min-w-[14px] h-3.5 px-0.5 rounded-full bg-red-600 text-white text-[8px] font-medium inline-flex items-center justify-center">
                    {t.badge}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      </div>
    );
  }

  /* ---------- Mobile top bar ---------- */
  function MobileTopBar({ title, back, right }) {
    const { allAlarms, set } = useStore();
    return (
      <div className="h-12 shrink-0 bg-white border-b border-ink-200 px-3 flex items-center gap-2 sticky top-0 z-20">
        {back ? (
          <IconBtn icon={Icon.chevLeft} label="返回" onClick={() => window.history.back()} />
        ) : (
          <IconBtn icon={Icon.menu} label="菜单" />
        )}
        <h1 className="flex-1 text-sm font-semibold text-ink-900 truncate">{title}</h1>
        <IconBtn icon={Icon.search} label="搜索" onClick={() => set({ cmdkOpen: true })} />
        {right}
      </div>
    );
  }

  /* ---------- Device frame ---------- */
  function MobileFrame({ children }) {
    return (
      <div className="mobile-frame mx-auto">
        <div className="mobile-screen">
          <div className="mobile-notch"></div>
          {/* status bar */}
          <div className="h-11 flex items-center justify-between px-7 pt-3 text-[11px] font-semibold text-ink-900">
            <span>9:41</span>
            <div className="flex items-center gap-1.5">
              <svg width="16" height="10" viewBox="0 0 16 10" fill="currentColor"><rect x="0" y="6" width="3" height="4" rx="0.5"/><rect x="4" y="4" width="3" height="6" rx="0.5"/><rect x="8" y="2" width="3" height="8" rx="0.5"/><rect x="12" y="0" width="3" height="10" rx="0.5"/></svg>
              <svg width="14" height="10" viewBox="0 0 14 10" fill="currentColor"><path d="M7 0C4 0 1.6 1 0 2.5l1 1.3C2.5 2.5 4.5 1.7 7 1.7s4.5.8 6 2.1l1-1.3C12.4 1 10 0 7 0Zm0 3.5c-1.7 0-3.2.6-4.4 1.6l1 1.3c.9-.8 2-1.2 3.4-1.2s2.5.4 3.4 1.2l1-1.3A6.8 6.8 0 0 0 7 3.5ZM7 7a2 2 0 0 0-1.5.7L7 9.5l1.5-1.8A2 2 0 0 0 7 7Z"/></svg>
              <div className="ml-1 relative w-6 h-3">
                <div className="absolute inset-0 ring-1 ring-ink-800 rounded-[3px]"></div>
                <div className="absolute right-[-2.5px] top-1 h-1 w-0.5 bg-ink-800 rounded-r-sm"></div>
                <div className="absolute left-0.5 top-0.5 bottom-0.5 w-[16px] bg-ink-800 rounded-[1.5px]"></div>
              </div>
            </div>
          </div>
          <div className="absolute inset-x-0 top-11 bottom-0 overflow-hidden flex flex-col bg-ink-50">
            {children}
          </div>
        </div>
      </div>
    );
  }

  Object.assign(window, { Sidebar, TopBar, PageHeader, CmdK, MobileFrame, MobileBottomNav, MobileTopBar, Logo, NAV });
})();
