// Main Solution Order Management app

// Permission context — available to all child views
const PermCtx = React.createContext({ perms: {}, currentUser: { id: '', name: '', team: '' } });
window.PermCtx = PermCtx;

const NAV_ITEMS = [
  { id: 'orders',    label: 'Orders',     th: 'คำสั่งซื้อ',   icon: 'list',     count: (userId, currentUser, perms) => {
    const orders = window.ORDERS || [];
    const viewScope = (perms || {})['View orders'] !== undefined ? (perms || {})['View orders'] : 'all';
    if (viewScope === false) return 0;
    if (viewScope === 'active') return orders.filter(o => o.status?.id === 'active').length;
    if (viewScope === 'assigned') {
      const ownerKey = currentUser?.ownerKey || '';
      return orders.filter(o => o.owner === userId || o.owner === ownerKey).length;
    }
    if (viewScope === 'own + team') {
      const myTeam = currentUser?.team || '';
      const ownerKey = currentUser?.ownerKey || '';
      return orders.filter(o => {
        if (o.owner === userId || o.owner === ownerKey) return true;
        if (!myTeam) return false;
        const users = window.USERS || [];
        const ownerUser = users.find(u => {
          if (u.id === o.owner) return true;
          const sn = (u.name || '').split(' ').map((p, i) => i === 0 ? p : (p[0] || '') + '.').join(' ');
          return sn === o.owner;
        });
        return ownerUser?.team === myTeam;
      }).length;
    }
    return orders.length; // 'all'
  } },
  { id: 'approvals', label: 'Approvals',  th: 'รออนุมัติ',     icon: 'check',    count: (userId) => {
    if (!userId) return 0;
    const workflows = window.DEFAULT_WORKFLOWS || {};
    return (window.ORDERS || []).filter(o => {
      if (o.status?.id !== 'pending_apv' && o.status?.id !== 'submitted') return false;
      // Merge stages across all products (same logic as approvals.jsx)
      const seenApprovers = new Map();
      (o.items || []).forEach(it => {
        (workflows[it.productId] || []).forEach((s, i) => {
          const key = s.approver;
          if (!seenApprovers.has(key) || s.slaH > seenApprovers.get(key).slaH) {
            seenApprovers.set(key, { ...s, stageOrder: i });
          }
        });
      });
      const merged = [...seenApprovers.values()].sort((a, b) => a.stageOrder - b.stageOrder);
      const stageIdx = Math.min(o.approvalStage || 0, merged.length - 1);
      return merged[stageIdx]?.approver === userId;
    }).length;
  }, alert: true },
  { id: 'provisioning', label: 'Provisioning', th: 'ดำเนินการ', icon: 'arrowRight', count: () => (window.ORDERS || []).filter(o => ['approved','provisioning'].includes(o.status?.id)).length },
  { id: 'catalog',   label: 'Catalog',    th: 'แค็ตตาล็อก',   icon: 'package',  count: () => (window.PRODUCTS || []).length },
  { id: 'customers', label: 'Customers',  th: 'ลูกค้า',       icon: 'building', count: () => (window.COMPANIES || []).length },
];

// ─── Loading screen ──────────────────────────────────────────────────────────
const LoadingScreen = () => (
  <div style={{
    minHeight: '100vh', background: 'var(--dark)',
    display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 16,
  }}>
    <img src="assets/true-business-logo.png" alt="True Business"
      style={{ height: 24, filter: 'brightness(0) invert(1)', opacity: 0.6 }}/>
    <div style={{ display: 'flex', gap: 6 }}>
      {[0,1,2].map(i => (
        <div key={i} style={{
          width: 7, height: 7, borderRadius: '50%', background: 'rgba(255,255,255,0.3)',
          animation: `dot-bounce 1s ${i * 0.18}s ease-in-out infinite`,
        }}/>
      ))}
    </div>
    <style>{`
      @keyframes dot-bounce { 0%,80%,100%{transform:scale(0.5);opacity:.3} 40%{transform:scale(1);opacity:1} }
    `}</style>
  </div>
);

const App = () => {
  const [t, setTweak] = useTweaks(window.TWEAK_DEFAULTS);
  const [view, setView] = useState('orders');
  const [openOrderId, setOpenOrderId] = useState(null);
  const [currentApprovalId, setCurrentApprovalId] = useState(null);

  // ── Password reset deep-link: #reset/<token> ─────────────────────────────
  const [resetToken, setResetToken] = useState(() => {
    const hash = window.location.hash.replace('#', '');
    if (hash.startsWith('reset/')) return hash.slice(6);
    return null;
  });

  // ── Auth state ──────────────────────────────────────────────────────────────
  const [authUser, setAuthUser] = useState(null);       // null = not logged in
  const [authChecking, setAuthChecking] = useState(true);

  // For System Admin demo: allow role override; others locked to their actual role
  const [demoRole, setDemoRole] = useState(null);       // null = use authUser.roleName

  useEffect(() => {
    const token = window.authToken?.get();
    if (!token) { setAuthChecking(false); return; }
    // Verify session and reload all live data in parallel
    Promise.all([
      window.apiFetch('/api/auth/me').then(r => r.ok ? r.json() : null),
      window.apiFetch('/api/init').then(r => r.ok ? r.json() : null),
    ]).then(([user, init]) => {
      if (user) setAuthUser(user);
      if (init) {
        if (init.products)          window.PRODUCTS           = init.products;
        if (init.orderStatuses)     window.ORDER_STATUSES     = init.orderStatuses;
        if (init.companies)         window.COMPANIES          = init.companies;
        if (init.contacts)          window.CONTACTS           = init.contacts;
        if (init.orders)            window.ORDERS             = init.orders;
        if (init.users)             window.USERS              = init.users;
        if (init.docTypes)          window.DOC_TYPES          = init.docTypes;
        if (init.docRequirements)   window.DOC_REQUIREMENTS   = init.docRequirements;
        if (init.workflows)         window.DEFAULT_WORKFLOWS  = init.workflows;
        if (init.categories)        window.PRODUCT_CATEGORIES = init.categories;
        if (init.conditions)        window.CONDITIONS_DATA    = init.conditions;
        if (init.roles)             window.ROLES              = init.roles;
        if (init.approvalConfigs)   window.APPROVAL_CONFIGS   = init.approvalConfigs;
      }
    }).catch(() => {}).finally(() => setAuthChecking(false));
  }, []);

  const handleLogin = (user) => {
    setAuthUser(user);
    setDemoRole(null);
  };

  const handleLogout = async () => {
    try { await window.apiFetch('/api/auth/logout', { method: 'POST' }); } catch {}
    window.authToken?.clear();
    setAuthUser(null);
    setDemoRole(null);
    setView('orders');
  };

  // Effective role name: demo override (admin only) or user's real role
  const isAdmin = authUser?.roleName === 'System Admin';
  const currentRoleName = (isAdmin && demoRole) ? demoRole : (authUser?.roleName || '');

  // Build permission context from logged-in user's role (+ admin demo override)
  const permCtxValue = useMemo(() => {
    if (!authUser) return { perms: {}, currentUser: { id: '', name: '', team: '', ownerKey: '' } };

    let perms = authUser.perms || {};
    // If admin is using demo role override, get that role's perms
    if (isAdmin && demoRole && demoRole !== authUser.roleName) {
      const roles = window.ROLES || [];
      const overrideRole = roles.find(r => r.label === demoRole);
      if (overrideRole) perms = overrideRole.perms || {};
    }

    const users = window.USERS || [];
    const cu = users.find(u => u.id === authUser.id) || authUser;
    const ownerKey = (cu.name || '').split(' ').map((p, i) => i === 0 ? p : (p[0] || '') + '.').join(' ');
    const currentUser = { id: cu.id || authUser.id, name: cu.name || authUser.name, team: cu.team || authUser.team || '', ownerKey };
    return { perms, currentUser };
  }, [authUser, demoRole, isAdmin]);

  // Normalize tweaks for downstream views: convert string sentinels back to JS values
  const tweaks = useMemo(() => ({
    ...t,
    slaOverride: t.slaOverride === 0 ? null : t.slaOverride,
    statusOverride: t.statusOverride === '__none__' ? null : t.statusOverride,
    hiddenProducts: PRODUCTS.filter(p => t['show_' + p.id] === false).map(p => p.id),
  }), [t]);

  const [createPreselect, setCreatePreselect] = useState(null);
  const [openCustomerId, setOpenCustomerId]   = useState(null);
  const [oneCallPrefill, setOneCallPrefill]   = useState(null);
  const [ocOrderId, setOcOrderId]             = useState(null);

  const openOrder    = (id) => { setOpenOrderId(id); setView('detail'); };
  const backToList   = () => { setOpenOrderId(null); setView('orders'); };
  const newOrder     = (preselect) => { setCreatePreselect(preselect || null); setView('create'); };
  const openCustomer = (id) => { setOpenCustomerId(id); setView('customers'); };
  const openOneCall  = () => { setOneCallPrefill(null); setOcOrderId(null); setView('onecall'); };

  // ── Deep-link: parse URL hash after login data is ready ─────────────────────
  // Supported:
  //   #order/SOL-2026-XXXX    → open order detail
  //   #approval/SOL-2026-XXXX → open approval inbox and jump to that order
  useEffect(() => {
    if (!authUser) return; // wait until logged in
    const hash = window.location.hash.replace('#', '');
    if (!hash) return;
    const [type, id] = hash.split('/');
    if (type === 'order' && id) {
      setOpenOrderId(id);
      setView('detail');
    } else if (type === 'approval' && id) {
      setCurrentApprovalId(id);
      setView('approvals');
    }
    // Clear hash after consuming so it doesn't re-trigger
    window.history.replaceState(null, '', window.location.pathname);
  }, [authUser]); // runs once when user becomes available

  const layout = t.layout || 'sidebar';

  // ── Auth gate ───────────────────────────────────────────────────────────────
  if (resetToken) return (
    <ResetPasswordView
      token={resetToken}
      onDone={() => {
        window.history.replaceState(null, '', window.location.pathname);
        setResetToken(null);
      }}
    />
  );
  if (authChecking) return <LoadingScreen/>;
  if (!authUser) return <LoginView onLogin={handleLogin}/>;

  return (
    <PermCtx.Provider value={permCtxValue}>
    <div style={{
      minHeight: '100vh',
      background: 'var(--bg)',
      display: layout === 'sidebar' ? 'grid' : 'flex',
      gridTemplateColumns: layout === 'sidebar' ? '220px 1fr' : undefined,
      flexDirection: layout === 'topnav' ? 'column' : undefined,
    }}>
{layout === 'sidebar' && <Sidebar current={view} setView={setView} onOpenOneCall={openOneCall} currentRoleName={currentRoleName} setDemoRole={setDemoRole} authUser={authUser} isAdmin={isAdmin} onLogout={handleLogout}/>}
      {layout === 'topnav'  && <TopNav current={view} setView={setView} onOpenOrder={openOrder}/>}

      <div style={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
        <TopBar layout={layout} setView={setView} onOpenOrder={openOrder} onOpenCustomer={openCustomer}/>
        <main style={{
          flex: 1, padding: layout === 'sidebar' ? '24px 28px 80px' : '24px 32px 80px',
          maxWidth: layout === 'topnav' ? 1440 : 'none',
          margin: layout === 'topnav' ? '0 auto' : undefined,
          width: '100%', boxSizing: 'border-box',
        }}>
          {view === 'orders'    && <OrderListView   tweaks={tweaks} onOpen={openOrder} onNew={newOrder}/>}
          {view === 'oclist'    && <OcOrderListView onNew={() => openOneCall()} onOpen={(id) => { setOcOrderId(id); setView('onecall'); }}/>}
          {view === 'onecall'   && <OneCallOrderView key={ocOrderId || oneCallPrefill?.companyId || 'new'} onBack={() => { const back = ocOrderId ? 'oclist' : (oneCallPrefill?.fromSolOrder ? 'provisioning' : 'orders'); setOneCallPrefill(null); setOcOrderId(null); setView(back); }} onComplete={(ocId, ocNumber) => {
            const fromSol = oneCallPrefill?.fromSolOrder;
            if (fromSol && ocId) {
              // Link the OC order to the SOL provisioning step and mark done
              window.apiFetch(`/api/orders/${fromSol.orderId}/prov-progress`, {
                method: 'PATCH',
                body: JSON.stringify({
                  ...(fromSol.stepId ? { stepId: fromSol.stepId } : { stepKey: fromSol.stepKey }),
                  status: 'done',
                  meta: { oneCallOrderId: ocId, oneCallOrderNumber: ocNumber },
                }),
              });
            }
            const back = ocOrderId ? 'oclist' : (fromSol ? 'provisioning' : 'orders');
            setOneCallPrefill(null); setOcOrderId(null); setView(back);
          }} prefill={oneCallPrefill} orderId={ocOrderId}/>}
          {view === 'detail'    && <OrderDetailView orderId={openOrderId} tweaks={tweaks} onBack={backToList}/>}
          {view === 'create'    && <CreateOrderView tweaks={tweaks} onBack={backToList} onComplete={backToList} preselect={createPreselect}/>}
          {view === 'provisioning' && <ProvisioningView onNavigateOneCall={data => { if (data?.openOrderId) { setOcOrderId(data.openOrderId); setOneCallPrefill(null); } else { setOneCallPrefill(data); setOcOrderId(null); } setView('onecall'); }}/>}
          {view === 'approvals' && <ApprovalsView   currentApprovalId={currentApprovalId} setCurrentApprovalId={setCurrentApprovalId}/>}
          {view === 'catalog'   && <CatalogView     tweaks={tweaks} onNew={newOrder}/>}
          {view === 'customers' && <CustomersView   onOpen={openOrder} onNew={newOrder} initialCustomerId={openCustomerId} onClearInitial={() => setOpenCustomerId(null)}/>}
          {view.startsWith('settings_') && (
            <SettingsLayout current={view} setView={setView}>
              {view === 'settings_catalog'  && <SettingsCatalogView/>}
              {view === 'settings_status'   && <SettingsStatusView/>}
              {view === 'settings_workflow' && <SettingsWorkflowView/>}
              {view === 'settings_docs'     && <SettingsDocumentsView/>}
              {view === 'settings_reasons'    && <SettingsReasonsView setView={setView}/>}
              {view === 'settings_provision' && <SettingsProvisionView/>}
              {view === 'settings_user'      && <SettingsUserView/>}
            </SettingsLayout>
          )}
        </main>
      </div>

      <TweaksUI t={t} setTweak={setTweak}/>
    </div>
    </PermCtx.Provider>
  );
};

// ---------- Sidebar (dark) ----------
const Sidebar = ({ current, setView, onOpenOneCall, currentRoleName, setDemoRole, authUser, isAdmin, onLogout }) => {
  const settingsActive = current.startsWith('settings_');
  const [settingsOpen, setSettingsOpen] = useState(settingsActive);
  const ordersActive = ['orders','detail','create','oclist','onecall'].includes(current);
  const [ordersOpen, setOrdersOpen] = useState(current === 'oclist' || current === 'onecall');
  useEffect(() => { if (current === 'oclist' || current === 'onecall') setOrdersOpen(true); }, [current]);
  const [userMenuOpen, setUserMenuOpen] = useState(false);
  const [showPwdModal, setShowPwdModal] = useState(false);
  const [showProfileModal, setShowProfileModal] = useState(false);
  const userMenuRef = useRef(null);
  const { perms = {}, currentUser = {} } = React.useContext(window.PermCtx);
  const canAdminSetting  = perms['Admin Setting']       === true;
  const canManageUsers   = perms['Manage users']        === true;
  const canApprove       = perms['Approve orders']      === true;
  const canProvisioning  = perms['Manage provisioning'] === true;
  const canEditCatalog   = perms['Edit catalog']        === true;
  const canViewCustomer  = perms['View customer']       === true;
  const hasSettingsAccess = canAdminSetting || canManageUsers;
  // Filter nav items based on permissions
  const visibleNavItems = NAV_ITEMS.filter(item => {
    if (item.id === 'approvals')     return canApprove;
    if (item.id === 'provisioning')  return canProvisioning || canAdminSetting;
    if (item.id === 'catalog')       return canEditCatalog;
    if (item.id === 'customers')     return canViewCustomer;
    return true; // orders, onecall always visible
  });
  // Filter settings sub-items based on permission
  const visibleSettingsItems = (window.SETTINGS_ITEMS || []).filter(s =>
    s.id === 'settings_user' ? (canAdminSetting || canManageUsers) : canAdminSetting
  );
  useEffect(() => { if (settingsActive) setSettingsOpen(true); }, [settingsActive]);
  useEffect(() => {
    if (!userMenuOpen) return;
    const onDoc = (e) => { if (userMenuRef.current && !userMenuRef.current.contains(e.target)) setUserMenuOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [userMenuOpen]);

  return (
  <>
  <aside style={{
    background: 'var(--panel)', color: 'var(--ink-2)',
    borderRight: '1px solid var(--line)',
    minHeight: '100vh', display: 'flex', flexDirection: 'column',
    position: 'sticky', top: 0, height: '100vh',
  }}>
    {/* Logo header */}
    <div style={{ padding: '18px 20px 16px' }}>
      <img src="assets/true-business-logo.png" alt="True Business" style={{
        height: 22, width: 'auto', maxWidth: 130, objectFit: 'contain', objectPosition: 'left center',
        display: 'block', marginBottom: 4,
      }}/>
      <div style={{ fontSize: 9.5, fontWeight: 500, color: 'var(--ink-4)', letterSpacing: '0.08em', textTransform: 'uppercase', marginTop: 4 }}>Order Management</div>
    </div>

    {/* Nav */}
    <nav style={{ padding: '4px 8px', flex: 1, overflowY: 'auto' }}>
      <div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 500, padding: '10px 12px 6px' }}>Workspace</div>
      {visibleNavItems.map(item => {
        const active = item.id === 'orders' ? ordersActive : current === item.id;
        const count = item.count?.(currentUser.id, currentUser, perms);
        const isOrders = item.id === 'orders';
        return (
          <React.Fragment key={item.id}>
            <button onClick={() => { setView(item.id); if (isOrders) setOrdersOpen(o => !o); }} style={{
              width: '100%', padding: '8px 10px 8px 12px',
              display: 'flex', alignItems: 'center', gap: 9,
              background: active ? 'rgba(227,6,19,0.07)' : 'transparent',
              border: 'none', borderRadius: 6,
              color: active ? 'var(--true-red)' : 'var(--ink-2)',
              fontFamily: 'Kanit, sans-serif', fontSize: 13, cursor: 'pointer',
              transition: 'background 120ms', textAlign: 'left',
              fontWeight: active ? 500 : 400,
            }} onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-2)'; }}
               onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}>
              <Icon name={item.icon} size={14} color={active ? 'var(--true-red)' : 'var(--ink-3)'}/>
              <span style={{ flex: 1 }}>{item.label}</span>
              {count != null && count > 0 && (
                <span className="num" style={{
                  fontSize: 10,
                  color: item.alert ? '#fff' : (active ? 'var(--true-red)' : 'var(--ink-3)'),
                  background: item.alert ? 'var(--true-red)' : (active ? 'rgba(227,6,19,0.12)' : 'var(--bg-2)'),
                  padding: '1px 6px', borderRadius: 10, fontWeight: 600,
                }}>{count}</span>
              )}
              {isOrders && (
                <span style={{ transition: 'transform 160ms', transform: ordersOpen ? 'rotate(90deg)' : 'rotate(0deg)', color: 'var(--ink-4)', marginLeft: 0 }}>
                  <Icon name="chevron" size={10}/>
                </span>
              )}
            </button>
            {isOrders && ordersOpen && (
              <div style={{ margin: '2px 0 2px 20px' }}>
                {[{ id: 'oclist', label: 'One Call', icon: 'phone' }].map(sub => {
                  const subActive = current === sub.id || current === 'onecall';
                  return (
                    <button key={sub.id} onClick={() => setView(sub.id)} style={{
                      width: '100%', padding: '7px 10px 7px 12px',
                      display: 'flex', alignItems: 'center', gap: 8,
                      background: subActive ? 'rgba(227,6,19,0.07)' : 'transparent',
                      border: 'none', borderRadius: 6,
                      color: subActive ? 'var(--true-red)' : 'var(--ink-3)',
                      fontFamily: 'Kanit, sans-serif', fontSize: 12,
                      cursor: 'pointer', textAlign: 'left',
                    }} onMouseEnter={e => { if (!subActive) { e.currentTarget.style.background = 'var(--bg-2)'; } }}
                       onMouseLeave={e => { if (!subActive) { e.currentTarget.style.background = 'transparent'; } }}>
                      <Icon name={sub.icon} size={12} color={subActive ? 'var(--true-red)' : 'var(--ink-4)'}/>
                      <span style={{ flex: 1 }}>{sub.label}</span>
                    </button>
                  );
                })}
              </div>
            )}
          </React.Fragment>
        );
      })}

      {hasSettingsAccess && (
        <>
        <div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 500, padding: '16px 12px 6px' }}>Account</div>

        <button onClick={() => setSettingsOpen(o => !o)} style={{
          width: '100%', padding: '8px 10px 8px 12px',
          display: 'flex', alignItems: 'center', gap: 9,
          background: settingsActive ? 'rgba(227,6,19,0.07)' : 'transparent',
          border: 'none', borderRadius: 6,
          color: settingsActive ? 'var(--true-red)' : 'var(--ink-2)',
          fontFamily: 'Kanit, sans-serif', fontSize: 13, cursor: 'pointer', textAlign: 'left',
          fontWeight: settingsActive ? 500 : 400,
        }} onMouseEnter={e => { if (!settingsActive) e.currentTarget.style.background = 'var(--bg-2)'; }}
           onMouseLeave={e => { if (!settingsActive) e.currentTarget.style.background = 'transparent'; }}>
          <Icon name="cog" size={14} color={settingsActive ? 'var(--true-red)' : 'var(--ink-3)'}/>
          <span style={{ flex: 1 }}>Settings</span>
          <span style={{ transition: 'transform 160ms', transform: settingsOpen ? 'rotate(90deg)' : 'rotate(0deg)', color: 'var(--ink-4)' }}>
            <Icon name="chevron" size={10}/>
          </span>
        </button>

        {settingsOpen && (
          <div style={{ margin: '2px 0 2px 20px' }}>
            {visibleSettingsItems.map(s => {
              const active = current === s.id;
              return (
                <button key={s.id} onClick={() => setView(s.id)} style={{
                  width: '100%', padding: '7px 10px 7px 12px',
                  display: 'flex', alignItems: 'center', gap: 8,
                  background: active ? 'rgba(227,6,19,0.07)' : 'transparent',
                  border: 'none', borderRadius: 6,
                  color: active ? 'var(--true-red)' : 'var(--ink-3)',
                  fontFamily: 'Kanit, sans-serif', fontSize: 12,
                  cursor: 'pointer', textAlign: 'left',
                }} onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-2)'; }}
                   onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}>
                  <Icon name={s.icon} size={12} color={active ? 'var(--true-red)' : 'var(--ink-4)'}/>
                  <span style={{ flex: 1 }}>{s.label}</span>
                </button>
              );
            })}
          </div>
        )}
        </>
      )}
    </nav>

    {/* User card */}
    <div ref={userMenuRef} style={{ borderTop: '1px solid var(--line)', position: 'relative' }}>
      {userMenuOpen && (
        <div style={{
          position: 'absolute', bottom: 'calc(100% + 6px)', left: 8, right: 8,
          background: 'var(--panel)',
          border: '1px solid var(--line)',
          borderRadius: 6,
          boxShadow: 'var(--shadow-modal)',
          padding: 4, zIndex: 30,
          fontFamily: 'Kanit, sans-serif', color: 'var(--ink)',
          overflow: 'hidden',
        }}>
          <div style={{ padding: '12px 14px 10px' }}>
            <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.01em' }}>{authUser?.name || '—'}</div>
            <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>{authUser?.username} · {currentRoleName}</div>
          </div>
          {isAdmin && (
            <div style={{ borderTop: '1px solid var(--line)', padding: '8px 14px 6px' }}>
              <div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6, display: 'flex', alignItems: 'center', gap: 5 }}>
                <Icon name="shield" size={9} color="var(--ink-4)"/>
                Demo · Switch role
              </div>
              {(window.ROLES || []).map(r => (
                <button key={r.id} onClick={() => { setDemoRole(r.label === authUser?.roleName ? null : r.label); setUserMenuOpen(false); }} style={{
                  width: '100%', padding: '5px 10px',
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  background: currentRoleName === r.label ? 'var(--bg-2)' : 'transparent',
                  border: 'none', borderRadius: 3, cursor: 'pointer',
                  color: 'var(--ink-2)',
                  fontFamily: 'Kanit, sans-serif', fontSize: 12, textAlign: 'left',
                  transition: 'background 100ms',
                }} onMouseEnter={e => { if (currentRoleName !== r.label) e.currentTarget.style.background = 'var(--bg-hover)'; }}
                   onMouseLeave={e => { if (currentRoleName !== r.label) e.currentTarget.style.background = 'transparent'; }}>
                  <span>{r.label}</span>
                  {currentRoleName === r.label && <Icon name="check" size={10} color="var(--positive)"/>}
                </button>
              ))}
            </div>
          )}
          <div style={{ borderTop: '1px solid var(--line)' }}/>
          <button onClick={() => { setShowProfileModal(true); setUserMenuOpen(false); }} style={lightMenuBtn}>
            <span style={{ width: 18, fontSize: 13 }}>👤</span>
            <span style={{ flex: 1 }}>My profile</span>
          </button>
          <button onClick={() => { setShowPwdModal(true); setUserMenuOpen(false); }} style={lightMenuBtn}>
            <span style={{ width: 18, fontSize: 13 }}>🔑</span>
            <span style={{ flex: 1 }}>เปลี่ยน Password</span>
          </button>
          {isAdmin && (
            <button onClick={() => { setView('settings_user'); setUserMenuOpen(false); }} style={lightMenuBtn}>
              <span style={{ width: 18, fontSize: 13 }}>👥</span>
              <span style={{ flex: 1 }}>User management</span>
            </button>
          )}
          <div style={{ borderTop: '1px solid var(--line)', margin: '4px 0' }}/>
          <button onClick={() => { setUserMenuOpen(false); onLogout(); }}
            style={{ ...lightMenuBtn, color: 'var(--negative)' }}>
            <Icon name="logOut" size={13}/>
            <span style={{ flex: 1 }}>ออกจากระบบ</span>
          </button>
        </div>
      )}
      <button onClick={() => setUserMenuOpen(o => !o)} style={{
        width: '100%', padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10,
        background: userMenuOpen ? 'var(--bg-2)' : 'transparent',
        border: 'none', cursor: 'pointer', textAlign: 'left',
        fontFamily: 'Kanit, sans-serif',
        transition: 'background 120ms',
      }} onMouseEnter={e => { if (!userMenuOpen) e.currentTarget.style.background = 'var(--bg-hover)'; }}
         onMouseLeave={e => { if (!userMenuOpen) e.currentTarget.style.background = 'transparent'; }}>
        <div style={{ position: 'relative' }}>
          <Avatar name={authUser?.name || '?'} size={30}/>
          <span style={{
            position: 'absolute', bottom: -1, right: -1,
            width: 7, height: 7, borderRadius: '50%',
            background: 'var(--positive)', border: '2px solid var(--panel)',
          }}/>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, color: 'var(--ink)', fontWeight: 500 }}>{authUser?.name || '—'}</div>
          <div style={{ fontSize: 10.5, color: 'var(--ink-4)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{currentRoleName}</div>
        </div>
        <span style={{ transform: userMenuOpen ? 'rotate(180deg)' : 'none', transition: 'transform 160ms', display: 'inline-flex', color: 'var(--ink-4)' }}>
          <Icon name="chevronDown" size={10}/>
        </span>
      </button>
    </div>
  </aside>
  {showPwdModal && <ChangePasswordModal onClose={() => setShowPwdModal(false)}/>}
  {showProfileModal && (
    <Modal open={true} title="My profile" subtitle="ข้อมูลส่วนตัวและการตั้งค่า"
      onClose={() => setShowProfileModal(false)} width={900}
      footer={<>
        <Button variant="ghost" onClick={() => setShowProfileModal(false)}>Close</Button>
        <Button variant="primary" icon="check" onClick={() => { setShowProfileModal(false); showToast('บันทึกข้อมูลแล้ว', { variant: 'success' }); }}>Save changes</Button>
      </>}>
      <ProfileTab/>
    </Modal>
  )}
  </>
  );
};

const darkMenuBtn = {
  width: '100%', padding: '10px 14px',
  display: 'flex', alignItems: 'center', gap: 10,
  background: 'transparent', border: 'none', cursor: 'pointer',
  borderRadius: 3, color: '#fff',
  fontFamily: 'Kanit, sans-serif', fontSize: 13, textAlign: 'left',
  transition: 'background 120ms',
};

const lightMenuBtn = {
  width: '100%', padding: '9px 14px',
  display: 'flex', alignItems: 'center', gap: 10,
  background: 'transparent', border: 'none', cursor: 'pointer',
  borderRadius: 4, color: 'var(--ink-2)',
  fontFamily: 'Kanit, sans-serif', fontSize: 13, textAlign: 'left',
  transition: 'background 120ms',
};

const ChangePasswordModal = ({ onClose }) => {
  const [cur, setCur] = useState('');
  const [next, setNext] = useState('');
  const [confirm, setConfirm] = useState('');
  const valid = next.length >= 8 && next === confirm && cur.length > 0;

  // Strength heuristic
  const checks = {
    len:  next.length >= 8,
    upper: /[A-Z]/.test(next),
    digit: /[0-9]/.test(next),
    sym:   /[^A-Za-z0-9]/.test(next),
  };
  const score = Object.values(checks).filter(Boolean).length;
  const strengthLabel = ['—','Very weak','Weak','Good','Strong'][score];
  const strengthColor = ['var(--ink-4)','var(--negative)','#d97b2e','#d97b2e','var(--positive)'][score];

  return (
    <Modal open={true} title="Change password" subtitle="อัปเดตรหัสผ่านสำหรับลงชื่อเข้าระบบ"
      onClose={onClose} width={460}
      footer={<>
        <Button variant="ghost" onClick={onClose}>Cancel</Button>
        <Button variant="primary" icon="check" disabled={!valid}
          onClick={async () => {
            try {
              const r = await window.apiFetch('/api/auth/change-password', {
                method: 'POST', body: JSON.stringify({ currentPassword: cur, newPassword: next }),
              });
              const d = await r.json();
              if (!r.ok) { showToast(d.error || 'เกิดข้อผิดพลาด', { variant: 'error' }); return; }
              onClose(); showToast('เปลี่ยนรหัสผ่านสำเร็จ', { variant: 'success' });
            } catch { showToast('เกิดข้อผิดพลาด', { variant: 'error' }); }
          }}>
          Update password
        </Button>
      </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field label="รหัสผ่านปัจจุบัน" required>
          <TextInput type="password" value={cur} onChange={e => setCur(e.target.value)} placeholder="••••••••"/>
        </Field>
        <Field label="รหัสผ่านใหม่" required hint="อย่างน้อย 8 ตัวอักษร ผสมตัวพิมพ์ใหญ่ ตัวเลข และสัญลักษณ์พิเศษ">
          <TextInput type="password" value={next} onChange={e => setNext(e.target.value)} placeholder="••••••••"/>
        </Field>
        {/* Strength meter */}
        {next.length > 0 && (
          <div style={{ marginTop: -8 }}>
            <div style={{ display: 'flex', gap: 4, marginBottom: 6 }}>
              {[1,2,3,4].map(i => (
                <div key={i} style={{
                  flex: 1, height: 3, borderRadius: 1,
                  background: i <= score ? strengthColor : 'var(--line-2)',
                  transition: 'background 120ms',
                }}/>
              ))}
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10.5 }}>
              <span style={{ color: strengthColor, fontWeight: 500 }}>{strengthLabel}</span>
              <span style={{ color: 'var(--ink-3)' }}>
                {Object.entries({
                  '8+ chars': checks.len,
                  'A-Z': checks.upper,
                  '0-9': checks.digit,
                  'Symbol': checks.sym,
                }).map(([k, v]) => (
                  <span key={k} style={{ marginLeft: 8, color: v ? 'var(--positive)' : 'var(--ink-4)' }}>
                    {v ? '✓' : '·'} {k}
                  </span>
                ))}
              </span>
            </div>
          </div>
        )}
        <Field label="ยืนยันรหัสผ่านใหม่" required
          error={confirm.length > 0 && confirm !== next ? 'รหัสผ่านไม่ตรงกับ' : null}>
          <TextInput type="password" value={confirm} onChange={e => setConfirm(e.target.value)} placeholder="••••••••"/>
        </Field>
      </div>
    </Modal>
  );
};

// ---------- Notification Bell ----------
const NotificationBell = ({ onOpenOrder, dark = false }) => {
  const [open, setOpen] = useState(false);
  const [read, setRead] = useState(() => {
    try { return JSON.parse(localStorage.getItem('sol_notif_read') || '[]'); } catch { return []; }
  });
  const ref = useRef(null);
  const { currentUser, perms } = React.useContext(window.PermCtx);
  const canApprove = perms['Approve orders'] === true;

  const notifications = useMemo(() => {
    const orders = window.ORDERS || [];
    const workflows = window.DEFAULT_WORKFLOWS || {};
    const items = [];

    orders.forEach(order => {
      const statusId = order.status?.id;

      // For approvers: orders submitted and waiting for their approval
      // Use merged stages across ALL products (same logic as approvals.jsx & SLATimeline)
      if (canApprove && (statusId === 'submitted' || statusId === 'pending_apv')) {
        const seenApprovers = new Map();
        (order.items || []).forEach(it => {
          (workflows[it.productId] || []).forEach((s, i) => {
            const key = s.approver;
            if (!seenApprovers.has(key) || s.slaH > seenApprovers.get(key).slaH) {
              seenApprovers.set(key, { ...s, stageOrder: i });
            }
          });
        });
        const mergedStages = [...seenApprovers.values()].sort((a, b) => a.stageOrder - b.stageOrder);
        if (mergedStages.length > 0) {
          const stageIdx = Math.min(order.approvalStage || 0, mergedStages.length - 1);
          const stage = mergedStages[stageIdx];
          if (stage?.approver === currentUser.id) {
            items.push({
              id: `apv-${order.id}`,
              orderId: order.id,
              type: 'pending_apv',
              icon: 'clock',
              color: '#f59e0b',
              title: `${order.id} รออนุมัติจากคุณ`,
              sub: order.company?.name || '',
              ts: order.updatedAt || order.createdAt || '',
            });
          }
        }
      }

      // For order owners: sent back (rejected, need to fix)
      if (statusId === 'sent_back' && order.owner === currentUser.id) {
        items.push({
          id: `sb-${order.id}`,
          orderId: order.id,
          type: 'sent_back',
          icon: 'alert',
          color: 'var(--negative)',
          title: `${order.id} ถูกส่งกลับ`,
          sub: 'กรุณาแก้ไขและส่งอีกครั้ง',
          ts: order.updatedAt || order.createdAt || '',
        });
      }

      // For order owners: approved
      if (statusId === 'approved' && order.owner === currentUser.id) {
        items.push({
          id: `apvd-${order.id}`,
          orderId: order.id,
          type: 'approved',
          icon: 'check',
          color: 'var(--positive)',
          title: `${order.id} ได้รับการอนุมัติแล้ว`,
          sub: order.company?.name || '',
          ts: order.updatedAt || order.createdAt || '',
        });
      }
    });

    return items.sort((a, b) => (b.ts || '').localeCompare(a.ts || ''));
  }, [currentUser, canApprove]);

  const unreadIds = notifications.filter(n => !read.includes(n.id)).map(n => n.id);
  const unreadCount = unreadIds.length;

  // Close on outside click
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const handleOpen = () => {
    setOpen(o => !o);
  };

  const markAllRead = (e) => {
    e && e.stopPropagation();
    const ids = notifications.map(n => n.id);
    setRead(ids);
    localStorage.setItem('sol_notif_read', JSON.stringify(ids));
  };

  const handleClickItem = (notif) => {
    const newRead = [...new Set([...read, notif.id])];
    setRead(newRead);
    localStorage.setItem('sol_notif_read', JSON.stringify(newRead));
    setOpen(false);
    onOpenOrder && onOpenOrder(notif.orderId);
  };

  const typeLabel = { pending_apv: 'รออนุมัติ', sent_back: 'ถูกส่งกลับ', approved: 'อนุมัติแล้ว' };

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button
        onClick={handleOpen}
        title="Notifications"
        style={{
          background: 'none', border: 'none', cursor: 'pointer',
          color: dark ? 'var(--dark-ink)' : 'var(--ink-2)',
          position: 'relative', padding: 4,
        }}>
        <Icon name="bell" size={15}/>
        {unreadCount > 0 && (
          <span style={{
            position: 'absolute', top: 0, right: 0,
            minWidth: 14, height: 14, padding: '0 3px',
            background: 'var(--accent-2)', borderRadius: 99,
            fontSize: 8.5, fontWeight: 700, color: '#fff',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxSizing: 'border-box', border: dark ? '1.5px solid var(--dark)' : '1.5px solid var(--panel)',
            lineHeight: 1,
          }}>
            {unreadCount > 9 ? '9+' : unreadCount}
          </span>
        )}
      </button>

      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 8px)', right: 0,
          width: 320, background: 'var(--panel)', border: '1px solid var(--line)',
          borderRadius: 6, boxShadow: 'var(--shadow-modal)', zIndex: 200,
          overflow: 'hidden',
        }}>
          {/* Header */}
          <div style={{
            padding: '11px 14px', borderBottom: '1px solid var(--line)',
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
              <span style={{ fontSize: 13, fontWeight: 600 }}>Notifications</span>
              {unreadCount > 0 && (
                <span style={{
                  fontSize: 10, fontWeight: 600, padding: '1px 6px',
                  background: 'var(--accent-2)', color: '#fff', borderRadius: 99,
                }}>
                  {unreadCount} ใหม่
                </span>
              )}
            </div>
            {unreadCount > 0 && (
              <button onClick={markAllRead} style={{
                background: 'none', border: 'none', cursor: 'pointer',
                fontSize: 11, color: 'var(--brand)', padding: 0, fontFamily: 'Kanit, sans-serif',
              }}>
                อ่านทั้งหมด
              </button>
            )}
          </div>

          {/* Items */}
          {notifications.length === 0 ? (
            <div style={{ padding: '28px 14px', textAlign: 'center', color: 'var(--ink-3)', fontSize: 12 }}>
              <div style={{ marginBottom: 8, opacity: 0.5 }}><Icon name="bell" size={28}/></div>
              ไม่มีการแจ้งเตือนตอนนี้
            </div>
          ) : (
            <div style={{ maxHeight: 380, overflowY: 'auto' }}>
              {notifications.map((n, i) => {
                const isUnread = !read.includes(n.id);
                return (
                  <div key={n.id} onClick={() => handleClickItem(n)}
                    style={{
                      padding: '10px 14px', cursor: 'pointer',
                      display: 'flex', alignItems: 'flex-start', gap: 10,
                      background: isUnread ? 'color-mix(in srgb, var(--brand) 5%, var(--panel))' : 'transparent',
                      borderBottom: i < notifications.length - 1 ? '1px solid var(--line)' : 'none',
                      transition: 'background 80ms',
                    }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = isUnread ? 'color-mix(in srgb, var(--brand) 5%, var(--panel))' : 'transparent'}>
                    {/* Icon */}
                    <div style={{
                      width: 30, height: 30, borderRadius: '50%', flexShrink: 0, marginTop: 1,
                      background: n.color + '20', display: 'flex', alignItems: 'center', justifyContent: 'center',
                      color: n.color,
                    }}>
                      <Icon name={n.icon} size={13}/>
                    </div>
                    {/* Text */}
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5, fontWeight: isUnread ? 600 : 400, lineHeight: 1.35 }}>{n.title}</div>
                      {n.sub && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 1 }}>{n.sub}</div>}
                      <div style={{ fontSize: 10, color: 'var(--ink-4)', marginTop: 3 }}>{typeLabel[n.type]}</div>
                    </div>
                    {/* Unread dot */}
                    {isUnread && (
                      <span style={{ width: 7, height: 7, borderRadius: '50%', background: n.color, flexShrink: 0, marginTop: 8 }}/>
                    )}
                  </div>
                );
              })}
            </div>
          )}
        </div>
      )}
    </div>
  );
};

// ---------- Top nav (alternate layout) ----------
const TopNav = ({ current, setView, onOpenOrder }) => {
  const [settingsOpen, setSettingsOpen] = useState(false);
  const settingsRef = useRef(null);
  useEffect(() => {
    if (!settingsOpen) return;
    const onDoc = (e) => { if (settingsRef.current && !settingsRef.current.contains(e.target)) setSettingsOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [settingsOpen]);
  const settingsActive = current.startsWith('settings_');

  return (
  <header style={{
    background: 'var(--dark)', color: 'var(--dark-ink)', position: 'sticky', top: 0, zIndex: 10,
    borderBottom: '1px solid var(--dark-3)',
  }}>
    <div style={{ maxWidth: 1440, margin: '0 auto', padding: '0 32px', height: 56, display: 'flex', alignItems: 'center', gap: 24 }}>
      <img src="assets/true-business-logo.png" alt="True Business" style={{
        height: 20, filter: 'brightness(0) invert(1)',
      }}/>
      <div style={{ width: 1, height: 24, background: 'var(--dark-3)' }}/>
      <div style={{ fontSize: 12.5, fontWeight: 500, color: '#fff' }}>
        B2B Solutions <span style={{ color: 'var(--dark-ink-2)', fontWeight: 400 }}> · Order Management</span>
      </div>

      <nav style={{ display: 'flex', alignItems: 'center', gap: 4, marginLeft: 'auto', marginRight: 'auto' }}>
        {NAV_ITEMS.map(item => {
          const active = current === item.id || (item.id === 'orders' && current === 'detail');
          return (
            <button key={item.id} onClick={() => setView(item.id)} style={{
              padding: '8px 14px',
              background: active ? 'var(--dark-3)' : 'transparent',
              border: 'none', borderRadius: 3, color: active ? '#fff' : 'var(--dark-ink)',
              fontFamily: 'Kanit, sans-serif', fontSize: 12.5, cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 7, position: 'relative',
            }}>
              <Icon name={item.icon} size={13}/>
              {item.label}
              {active && <span style={{ position: 'absolute', left: 8, right: 8, bottom: -8, height: 2, background: 'var(--accent-2)' }}/>}
            </button>
          );
        })}
      </nav>

      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div ref={settingsRef} style={{ position: 'relative' }}>
          <button onClick={() => setSettingsOpen(o => !o)} style={{
            background: settingsActive || settingsOpen ? 'var(--dark-3)' : 'transparent',
            border: 'none', cursor: 'pointer',
            color: settingsActive || settingsOpen ? '#fff' : 'var(--dark-ink)',
            padding: '8px 10px', borderRadius: 3,
            display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'Kanit, sans-serif', fontSize: 12.5,
          }}>
            <Icon name="cog" size={13}/>
            <span style={{ transform: settingsOpen ? 'rotate(180deg)' : 'none', transition: 'transform 160ms', display: 'inline-flex' }}>
              <Icon name="chevronDown" size={9}/>
            </span>
          </button>
          {settingsOpen && (
            <div style={{
              position: 'absolute', top: '100%', right: 0, marginTop: 6,
              background: 'var(--panel)', color: 'var(--ink)',
              border: '1px solid var(--line)', borderRadius: 4,
              boxShadow: 'var(--shadow-pop)', minWidth: 220, padding: 4, zIndex: 100,
            }}>
              <div className="eyebrow" style={{ padding: '8px 10px 6px' }}>Settings</div>
              {SETTINGS_ITEMS.map(s => {
                const active = current === s.id;
                return (
                  <button key={s.id} onClick={() => { setView(s.id); setSettingsOpen(false); }} style={{
                    width: '100%', padding: '8px 10px',
                    display: 'flex', alignItems: 'center', gap: 10,
                    background: active ? 'var(--bg-2)' : 'transparent', border: 'none',
                    borderRadius: 3, cursor: 'pointer', textAlign: 'left',
                    color: 'var(--ink)', fontFamily: 'Kanit, sans-serif', fontSize: 12.5,
                  }} onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-hover)'; }}
                     onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}>
                    <Icon name={s.icon} size={13}/>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontWeight: active ? 500 : 400 }}>{s.label}</div>
                      <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{s.th}</div>
                    </div>
                  </button>
                );
              })}
            </div>
          )}
        </div>
        <NotificationBell onOpenOrder={onOpenOrder} dark={true}/>
        <Avatar name="ธีระพงษ์ ม." size={28}/>
      </div>
    </div>
  </header>
  );
};

// ---------- Top bar (only for sidebar layout) ----------
const TopBar = ({ layout, setView, onOpenOrder, onOpenCustomer }) => {
  const [query, setQuery]   = useState('');
  const [open, setOpen]     = useState(false);
  const wrapRef             = useRef(null);

  // Close dropdown when clicking outside
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const results = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return null;
    const orders = (window.ORDERS || []).filter(o =>
      o.id?.toLowerCase().includes(q) ||
      o.company?.name?.toLowerCase().includes(q)
    ).slice(0, 5).map(o => ({
      type: 'order', id: o.id,
      label: o.id,
      sub: o.company?.name || '',
      tag: o.status?.label || '',
      color: o.status?.color || 'var(--ink-3)',
    }));

    const companies = (window.COMPANIES || []).filter(c =>
      c.name?.toLowerCase().includes(q) ||
      c.taxId?.toLowerCase().includes(q) ||
      c.sector?.toLowerCase().includes(q) ||
      c.province?.toLowerCase().includes(q)
    ).slice(0, 5).map(c => ({
      type: 'company', id: c.id,
      label: c.name,
      sub: [c.sector, c.province].filter(Boolean).join(' · '),
    }));

    const products = (window.PRODUCTS || []).filter(p =>
      p.name?.toLowerCase().includes(q) ||
      p.nameTh?.toLowerCase().includes(q) ||
      p.category?.toLowerCase().includes(q)
    ).slice(0, 4).map(p => ({
      type: 'product', id: p.id,
      label: p.name,
      sub: p.nameTh || '',
      color: p.color,
    }));

    return { orders, companies, products, total: orders.length + companies.length + products.length };
  }, [query]);

  const handleSelect = (item) => {
    setQuery(''); setOpen(false);
    if (item.type === 'order')   { onOpenOrder(item.id); }
    if (item.type === 'company') { onOpenCustomer(item.id); }
    if (item.type === 'product') { setView('catalog'); }
  };

  const highlight = (text) => {
    const q = query.trim();
    if (!q) return text;
    const idx = text.toLowerCase().indexOf(q.toLowerCase());
    if (idx === -1) return text;
    return <>{text.slice(0, idx)}<mark style={{ background: 'var(--brand-bg)', color: 'var(--brand)', borderRadius: 2, padding: '0 1px' }}>{text.slice(idx, idx + q.length)}</mark>{text.slice(idx + q.length)}</>;
  };

  const Section = ({ label, items, icon }) => items.length === 0 ? null : (
    <>
      <div style={{ padding: '6px 12px 4px', fontSize: 9.5, color: 'var(--ink-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.07em', display: 'flex', alignItems: 'center', gap: 5 }}>
        <Icon name={icon} size={9}/>{label}
      </div>
      {items.map(item => (
        <div key={item.id} onClick={() => handleSelect(item)}
          style={{ padding: '7px 14px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 10, transition: 'background 80ms' }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
          {item.color && <span style={{ width: 7, height: 7, borderRadius: '50%', background: item.color, flexShrink: 0 }}/>}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{highlight(item.label)}</div>
            {item.sub && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 1 }}>{item.sub}</div>}
          </div>
          {item.tag && <span style={{ fontSize: 10, padding: '1px 6px', background: (item.color||'#888')+'18', color: item.color||'var(--ink-3)', borderRadius: 2, flexShrink: 0 }}>{item.tag}</span>}
        </div>
      ))}
    </>
  );

  if (layout === 'topnav') return null;
  return (
    <header style={{
      height: 56, borderBottom: '1px solid var(--line)',
      background: 'var(--panel)', display: 'flex', alignItems: 'center',
      padding: '0 28px', gap: 16, position: 'sticky', top: 0, zIndex: 10,
    }}>
      <div ref={wrapRef} style={{ position: 'relative', width: 320 }}>
        <span style={{ position: 'absolute', left: 9, top: '50%', transform: 'translateY(-50%)', color: 'var(--ink-3)', pointerEvents: 'none' }}>
          <Icon name="search" size={13}/>
        </span>
        <input
          value={query}
          onChange={e => { setQuery(e.target.value); setOpen(true); }}
          onFocus={() => { if (query) setOpen(true); }}
          onKeyDown={e => { if (e.key === 'Escape') { setQuery(''); setOpen(false); } }}
          placeholder="ค้นหา Order, Company, Product…"
          style={{ ...inputStyle, paddingLeft: 30, paddingRight: query ? 28 : 12, fontSize: 12, border: '1px solid transparent', background: 'var(--bg-2)', transition: 'border-color 120ms', width: '100%', boxSizing: 'border-box' }}
          onFocusCapture={e => e.target.style.borderColor = 'var(--line)'}
          onBlurCapture={e => e.target.style.borderColor = 'transparent'}
        />
        {query && (
          <button onClick={() => { setQuery(''); setOpen(false); }} style={{ position: 'absolute', right: 8, top: '50%', transform: 'translateY(-50%)', background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-3)', padding: 2 }}>
            <Icon name="close" size={10}/>
          </button>
        )}

        {/* Results dropdown */}
        {open && results && (
          <div style={{
            position: 'absolute', top: '100%', left: 0, right: 0, marginTop: 4,
            background: 'var(--panel)', border: '1px solid var(--line)',
            borderRadius: 4, boxShadow: 'var(--shadow-modal)',
            zIndex: 50, maxHeight: 400, overflowY: 'auto',
          }}>
            {results.total === 0 ? (
              <div style={{ padding: '16px 14px', fontSize: 12, color: 'var(--ink-4)', textAlign: 'center' }}>
                ไม่พบผลลัพธ์สำหรับ "{query}"
              </div>
            ) : (
              <>
                <Section label="Orders" icon="list"   items={results.orders}/>
                <Section label="Companies" icon="building" items={results.companies}/>
                <Section label="Products"  icon="package" items={results.products}/>
              </>
            )}
          </div>
        )}
      </div>

      <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--ink-3)' }}>
          <Icon name="calendar" size={12}/>
          <span className="num" style={{ color: 'var(--ink-2)', fontWeight: 500 }}>28 May 2026</span>
        </div>
        <div style={{ width: 1, height: 18, background: 'var(--line)' }}/>
        <NotificationBell onOpenOrder={onOpenOrder}/>
      </div>
    </header>
  );
};

// ---------- Tweaks panel ----------
const TweaksUI = ({ t, setTweak }) => {
  const statusOptions = [
    { value: '__none__', label: '— Use order default —' },
    ...ORDER_STATUSES.map(s => ({ value: s.id, label: s.label })),
  ];

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Layout"/>
      <TweakRadio  label="Navigation" value={t.layout}  options={[{value:'sidebar',label:'Sidebar'},{value:'topnav',label:'Top nav'}]} onChange={v => setTweak('layout', v)}/>

      <TweakSection label="Orders list"/>
      <TweakRadio  label="View" value={t.listView} options={[{value:'table',label:'Table'},{value:'card',label:'Cards'},{value:'kanban',label:'Kanban'}]} onChange={v => setTweak('listView', v)}/>

      <TweakSection label="SLA & timeline (in detail view)"/>
      <TweakRadio  label="Timeline style" value={t.slaViz} options={[{value:'stepper',label:'Stepper'},{value:'gantt',label:'Gantt'}]} onChange={v => setTweak('slaViz', v)}/>
      <TweakSlider label="SLA override" value={t.slaOverride} min={0} max={21} step={1} unit={t.slaOverride === 0 ? ' (default)' : ' วัน'} onChange={v => setTweak('slaOverride', v)}/>

      <TweakSection label="Order status (in detail view)"/>
      <TweakSelect label="Status override" value={t.statusOverride} options={statusOptions} onChange={v => setTweak('statusOverride', v)}/>

      <TweakSection label="Products shown"/>
      {PRODUCTS.map(p => (
        <TweakToggle key={p.id} label={p.name} value={t['show_' + p.id] !== false} onChange={v => setTweak('show_' + p.id, v)}/>
      ))}
    </TweaksPanel>
  );
};

(window._apiReady || Promise.resolve()).then(() => {
  ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
});
