/* =====================================================================
   AI-COS — App shell: sidebar nav + topbar + readiness pill
   ===================================================================== */
function Sidebar({ active, onNav, onLogout }) {
  const DB = window.DB;
  const ESS = ['dashboard', 'schedule', 'jobs', 'assets', 'certs', 'qms', 'documents', 'reports'];
  const ESS_LABEL = { schedule: 'Email Reminders', qms: 'NCR & CAPA' };
  const isAdmin = window.CAL && CAL.user && (CAL.user.role === 'Admin' || CAL.user.role === 'Super Admin');
  /* Live sidebar badges computed from the registers (never static). */
  const _js = (j) => ({ 'In progress': 'In Calibration', 'Review': 'QA/QC Review', 'Approved': 'Certified' }[j.stage] || j.stage);
  const LIVE_BADGE = {
    jobs: DB.jobs.filter((j) => !['Certified', 'Dispatched'].includes(_js(j))).length,
    schedule: DB.monitors.filter((m) => m.status !== 'Retired' && m.due && (new Date(m.due) - DB.TODAY) / 864e5 <= 30).length,
    qms: DB.capa.filter((x) => x.status !== 'Closed').length,
  };
  const groups = DB.nav
    .map((g) => {
      const items = g.items.filter((it) => ESS.includes(it.id)).map((it) => ({ ...it, label: ESS_LABEL[it.id] || it.label, phase: undefined, badge: LIVE_BADGE[it.id] || 0, badgeAmber: it.id === 'qms' }));
      // Surface Customers as its own sidebar entry, just before Equipment & Assets
      const ai = items.findIndex((it) => it.id === 'assets');
      if (ai >= 0) items.splice(ai, 0, { id: 'customers', label: 'Customers', icon: 'briefcase', badge: (DB.customers || []).length || 0 });
      return { ...g, items };
    })
    .filter((g) => g.items.length)
    .concat(isAdmin ? [{ group: 'Administration', items: [{ id: 'users', label: 'Users & Settings', icon: 'settings' }] }] : []);
  return (
    <aside className="sidebar">
      <div className="brand">
        <BrandMark size={36} light />
        <div>
          <div className="brand-name" style={{ fontSize: 15, lineHeight: 1.15 }}>Al Duqum Al Masiya</div>
          <div className="brand-sub">AI-COS Essential</div>
        </div>
      </div>

      <nav className="nav">
        {groups.map((grp) => (
          <div key={grp.group}>
            <div className="nav-group-label">{grp.group}</div>
            {grp.items.map((it) => (
              <div key={it.id} className={`nav-item${active === it.id ? ' active' : ''}`} onClick={() => onNav(it.id)}>
                <Icon name={it.icon} size={18} className="nav-ico" />
                <span>{it.label}</span>
                {it.badge ? <span className={`nav-badge${it.badgeAmber ? ' amber' : ''}`}>{it.badge}</span>
                  : it.phase ? <span className="nav-phase">{it.phase}</span> : null}
              </div>
            ))}
          </div>
        ))}
      </nav>

      <div className="side-foot">
        {(() => { const R = window.calReadiness ? window.calReadiness() : DB.readiness; return (
        <div className="readiness-card" onClick={() => onNav('dashboard')}>
          <div className="row" style={{ justifyContent: 'space-between' }}>
            <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.5px', color: '#9fb4d0', textTransform: 'uppercase' }}>Audit readiness</span>
            <Icon name="shield" size={13} style={{ color: 'var(--primary-500)' }} />
          </div>
          <div className="row" style={{ gap: 10, marginTop: 8, alignItems: 'flex-end' }}>
            <span style={{ fontSize: 30, fontWeight: 800, color: '#fff', lineHeight: 1, letterSpacing: '-1px' }}>{R.score}</span>
            <span style={{ fontSize: 12, color: '#7e94b0', marginBottom: 3 }}>/ 100</span>
            <span className={'badge ' + (R.score >= 85 ? 'b-ok' : R.score >= 70 ? 'b-warn' : 'b-bad')} style={{ marginLeft: 'auto', marginBottom: 2 }}>{R.verdict || 'Audit-ready'}</span>
          </div>
          <div className="progress" style={{ marginTop: 9, height: 5, background: '#0a1c30' }}>
            <i style={{ width: `${R.score}%`, background: R.score >= 85 ? 'linear-gradient(90deg, var(--primary-500), #58d6a6)' : R.score >= 70 ? 'linear-gradient(90deg, #c9820a, #e8b34b)' : 'linear-gradient(90deg, #b5341a, #e0483c)' }} />
          </div>
        </div>
        ); })()}
        <div className="nav-item" style={{ marginTop: 6, color: '#8aa0bd' }} onClick={onLogout}>
          <Icon name="logout" size={17} className="nav-ico" /><span>Sign out</span>
        </div>
      </div>
    </aside>
  );
}

function Topbar({ title, crumb, onOpenNotif, onNav, onLogout }) {
  const [menu, setMenu] = useState(false);
  const onSearch = (e) => { if (e.key === 'Enter' && e.target.value.trim()) window._search(e.target.value.trim()); };
  const u = (window.CAL && CAL.user) || { name: '—', role: '', email: '' };
  const initials = (u.name || '—').split(/\s+/).map((w) => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();
  const isAdmin = u.role === 'Admin' || u.role === 'Super Admin';
  // Bell dot lights up for unread personal notifications or overdue calibrations.
  const _DB = window.DB || {};
  const myUnread = (_DB.notifications || []).filter((n) => n.user === u.id && !n.read).length;
  const overdueN = (_DB.monitors || []).filter((m) => m.status !== 'Retired' && m.due && new Date(m.due) < (_DB.TODAY || new Date())).length;
  const showDot = myUnread > 0 || overdueN > 0;
  return (
    <header className="topbar">
      <div className="col" style={{ gap: 1 }}>
        <div className="breadcrumb"><span>AI-COS</span><Icon name="chevR" size={13} /><b>{crumb || title}</b></div>
      </div>
      <div className="spacer" />
      <div className="searchbox" onClick={(e) => e.currentTarget.querySelector('input').focus()}>
        <Icon name="search" size={16} />
        <input placeholder="Search assets, jobs, certificates, customers…" onKeyDown={onSearch} />
        <kbd>⌘K</kbd>
      </div>
      <button className="icon-btn" onClick={onOpenNotif} title="Notifications">
        <Icon name="bell" size={17} />{showDot && <span className="dot-badge" />}
      </button>
      <div className="vr" />
      <div style={{ position: 'relative' }}>
        <div className="row" style={{ gap: 9, cursor: 'pointer' }} onClick={() => setMenu((m) => !m)}>
          <span className="avatar" style={{ background: 'var(--primary-600)' }}>{initials}</span>
          <div className="col" style={{ gap: 0, lineHeight: 1.25 }}>
            <span style={{ fontSize: 13, fontWeight: 700 }}>{u.name}</span>
            <span style={{ fontSize: 11, color: 'var(--text-3)' }}>{u.role}</span>
          </div>
          <Icon name="chevD" size={14} style={{ color: 'var(--text-3)' }} />
        </div>
        {menu && (
          <React.Fragment>
            <div style={{ position: 'fixed', inset: 0, zIndex: 70 }} onClick={() => setMenu(false)} />
            <div className="popover" style={{ right: 0, top: 'calc(100% + 8px)', minWidth: 210 }}>
              <div style={{ padding: '6px 10px 8px', borderBottom: '1px solid var(--border)', marginBottom: 4 }}>
                <div style={{ fontSize: 12.5, fontWeight: 700 }}>{u.name}</div>
                <div className="faint" style={{ fontSize: 11 }}>{u.email || ''} · {window.DB.company.name}</div>
              </div>
              {isAdmin && <div className="pop-item" onClick={() => { setMenu(false); onNav && onNav('users'); }}><Icon name="settings" size={14} />Users &amp; settings</div>}
              <div className="pop-item" onClick={() => { setMenu(false); window.openChangePassword && window.openChangePassword(); }}><Icon name="lock" size={14} />Change password</div>
              <div className="pop-item" style={{ color: 'var(--bad)' }} onClick={() => { setMenu(false); onLogout && onLogout(); }}><Icon name="logout" size={14} />Sign out</div>
            </div>
          </React.Fragment>
        )}
      </div>
    </header>
  );
}

/* ---- AI assistant slide-over ---- */
function AIAssistant({ open, onClose, onNav }) {
  const DB = window.DB;
  return (
    <Drawer open={open} onClose={onClose} width={440}>
      <div className="drawer-head" style={{ background: 'linear-gradient(120deg, var(--ai-bg), #fff)' }}>
        <span className="ai-badge-ico" style={{ width: 34, height: 34 }}><Icon name="sparkles" size={18} fill /></span>
        <div style={{ flex: 1 }}>
          <div style={{ fontWeight: 750, fontSize: 15 }}>Compliance Intelligence</div>
          <div className="faint" style={{ fontSize: 12 }}>Advisory · logged · human-confirmed</div>
        </div>
        <button className="icon-btn" onClick={onClose}><Icon name="x" size={17} /></button>
      </div>
      <div className="drawer-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {(() => { const R = window.calReadiness ? window.calReadiness() : DB.readiness; const neg = R.factors.filter((f) => f.value < 0); return (
        <div className="card card-pad" style={{ background: 'linear-gradient(140deg, var(--navy-900), var(--navy-800))', color: '#fff', border: 'none' }}>
          <div className="row" style={{ justifyContent: 'space-between' }}>
            <span style={{ fontSize: 12, color: '#9fb4d0', fontWeight: 600 }}>Live audit-readiness</span>
            <Badge kind={R.score >= 85 ? 'ok' : R.score >= 70 ? 'warn' : 'bad'}>{R.verdict}</Badge>
          </div>
          <div className="row" style={{ gap: 8, marginTop: 6, alignItems: 'flex-end' }}>
            <span style={{ fontSize: 38, fontWeight: 800, lineHeight: 1 }}>{R.score}</span><span style={{ color: '#7e94b0', marginBottom: 5 }}>/ 100</span>
          </div>
          <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 6 }}>
            {neg.length ? neg.map((f, i) => (
              <div key={i} className="row" style={{ justifyContent: 'space-between', fontSize: 12 }}>
                <span style={{ color: '#cdd9ea' }}>{f.label}</span>
                <span style={{ color: '#ff9b8f', fontWeight: 700 }}>{f.value}</span>
              </div>
            )) : <span style={{ fontSize: 12, color: '#cdd9ea' }}>No deductions — keep records current.</span>}
          </div>
        </div>
        ); })()}
        {(window.calGuide ? window.calGuide().filter((g) => g.level !== 'ok').slice(0, 6) : []).map((g, i) => (
          <AINote key={i} title={{ jobs: 'Calibration jobs', assets: 'Asset management', qms: 'NCR & CAPA', documents: 'Document control', schedule: 'Email reminders', certs: 'Certificates', dashboard: 'Overview' }[g.module] || 'Guidance'} action="Open" onAction={() => { onClose(); onNav(g.go || g.module); }}>
            {g.text}
          </AINote>
        ))}
        <div className="faint" style={{ fontSize: 11.5, textAlign: 'center', padding: '4px 16px' }}>
          AI outputs never become records on their own. Each suggestion requires a human action and is written to the audit trail.
        </div>
      </div>
    </Drawer>
  );
}

/* ---- Notifications ---- */
function NotifPanel({ open, onClose, onNav }) {
  /* Live notifications derived from the registers — no canned items. */
  const DB = window.DB;
  const items = [];
  const _d = (x) => { const d = new Date(x); return isNaN(d) ? null : d; };
  DB.cylinders.filter((c) => c.status === 'Active' && _d(c.exp) && _d(c.exp) < DB.TODAY).forEach((c) =>
    items.push({ ico: 'x-circle', tone: 'bad', t: 'Cylinder ' + c.id + ' expired', s: (c.mix || '') + ' · replace before the next calibration', nav: 'assets' }));
  const dueToday = DB.monitors.filter((m) => m.status !== 'Retired' && _d(m.due) && _d(m.due).toDateString() === DB.TODAY.toDateString());
  if (dueToday.length) items.push({ ico: 'calendar', tone: 'bad', t: dueToday.length + ' calibration(s) due today', s: dueToday.slice(0, 3).map((m) => m.id).join(', '), nav: 'schedule' });
  const od = DB.monitors.filter((m) => m.status !== 'Retired' && _d(m.due) && _d(m.due) < DB.TODAY);
  if (od.length) items.push({ ico: 'alert', tone: 'bad', t: od.length + ' asset(s) overdue for calibration', s: 'Queue reminders or raise jobs', nav: 'schedule' });
  const certExp = DB.certificates.filter((ct) => ct.status === 'Valid' && _d(ct.certExpiry || ct.due) && _d(ct.certExpiry || ct.due) < DB.TODAY);
  if (certExp.length) items.push({ ico: 'certificate', tone: 'bad', t: certExp.length + ' certificate(s) expired', s: 'Overdue certificates — schedule recalibration', nav: 'certs' });
  const warr = DB.monitors.filter((m) => m.status !== 'Retired' && _d(m.warranty) && _d(m.warranty) >= DB.TODAY && (_d(m.warranty) - DB.TODAY) / 864e5 <= 30);
  if (warr.length) items.push({ ico: 'clock', tone: 'warn', t: warr.length + ' warranty(ies) expiring within 30 days', s: warr.slice(0, 3).map((m) => m.id).join(', '), nav: 'assets' });
  const rep = DB.monitors.filter((m) => m.status === 'Under repair');
  if (rep.length) items.push({ ico: 'wrench', tone: 'warn', t: rep.length + ' instrument(s) under repair', s: 'Awaiting return to service', nav: 'assets' });
  DB.jobs.filter((j) => ({ 'Review': 1, 'QA/QC Review': 1 })[j.stage]).forEach((j) =>
    items.push({ ico: 'flag', tone: 'info', t: j.id + ' awaiting QA/QC review', s: (DB.custById(j.customer) || {}).name + ' · ' + (j.items || 0) + ' item(s)', nav: 'jobs' }));
  DB.capa.filter((x) => x.status !== 'Closed' && _d(x.due) && _d(x.due) < DB.TODAY).forEach((x) =>
    items.push({ ico: 'clock', tone: 'warn', t: x.id + ' overdue', s: x.title || 'Corrective action past due', nav: 'qms' }));
  DB.certificates.slice(0, 2).forEach((ct) =>
    items.push({ ico: 'certificate', tone: 'ok', t: 'Certificate ' + ct.id + ' issued', s: (ct.model || '') + ' · ' + (ct.serial || ''), nav: 'certs' }));

  // Personal notifications for the signed-in user (e.g. job assignments)
  const me = window.CAL && CAL.user ? CAL.user.id : null;
  const mine = (DB.notifications || []).filter((n) => n.user === me)
    .slice().sort((a, b) => new Date(b.date) - new Date(a.date));
  const unread = mine.filter((n) => !n.read);
  const openMine = (n) => { window.dbUpdate && window.dbUpdate('notifications', 'id', n.id, { read: true }); onClose(); if (n.jobId && window._openJob) window._openJob(n.jobId); };
  const markAll = () => { unread.forEach((n) => window.dbUpdate && window.dbUpdate('notifications', 'id', n.id, { read: true })); };

  return (
    <Drawer open={open} onClose={onClose} width={400}>
      <div className="drawer-head">
        <Icon name="bell" size={18} /><div style={{ flex: 1, fontWeight: 750, fontSize: 15 }}>Notifications</div>
        {unread.length > 0 && <button className="icon-btn" style={{ width: 'auto', padding: '0 8px', fontSize: 12, fontWeight: 600, color: 'var(--primary-600)' }} onClick={markAll}>Mark all read</button>}
        <button className="icon-btn" onClick={onClose}><Icon name="x" size={17} /></button>
      </div>
      <div className="drawer-body" style={{ padding: 14 }}>
        {mine.length > 0 && (
          <div style={{ marginBottom: 8 }}>
            <div className="eyebrow" style={{ fontSize: 9.5, padding: '2px 8px 6px' }}>For you</div>
            {mine.slice(0, 8).map((n) => (
              <div key={n.id} className="row" style={{ gap: 11, padding: '11px 8px', borderBottom: '1px solid var(--border)', alignItems: 'flex-start', cursor: 'pointer', borderRadius: 8, background: n.read ? 'transparent' : 'var(--info-bg)' }} onClick={() => openMine(n)}>
                <span className="kpi-ico" style={{ background: n.read ? 'var(--bg)' : 'var(--info-bg)', color: 'var(--primary-600)', width: 32, height: 32 }}><Icon name="workflow" size={16} /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 650, fontSize: 13 }}>{n.title}{!n.read && <span style={{ display: 'inline-block', width: 7, height: 7, borderRadius: '50%', background: 'var(--primary-600)', marginLeft: 6, verticalAlign: 'middle' }} />}</div>
                  <div className="faint" style={{ fontSize: 12, marginTop: 1 }}>{n.body}</div>
                </div>
              </div>
            ))}
          </div>
        )}
        {mine.length > 0 && items.length > 0 && <div className="eyebrow" style={{ fontSize: 9.5, padding: '6px 8px 6px' }}>Lab alerts</div>}
        {!items.length && !mine.length && <div className="faint" style={{ textAlign: 'center', padding: '30px 16px', fontSize: 13 }}>You're all caught up — nothing needs attention.</div>}
        {items.map((it, i) => {
          const bg = { bad: 'var(--bad-bg)', ok: 'var(--ok-bg)', warn: 'var(--warn-bg)', info: 'var(--info-bg)' }[it.tone];
          const fg = { bad: 'var(--bad)', ok: 'var(--ok)', warn: 'var(--warn)', info: 'var(--primary-600)' }[it.tone];
          return (
            <div key={i} className="row" style={{ gap: 11, padding: '11px 8px', borderBottom: '1px solid var(--border)', alignItems: 'flex-start', cursor: 'pointer', borderRadius: 8 }} onClick={() => { onClose(); onNav && onNav(it.nav); }}>
              <span className="kpi-ico" style={{ background: bg, color: fg, width: 32, height: 32 }}><Icon name={it.ico} size={16} /></span>
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 650, fontSize: 13 }}>{it.t}</div>
                <div className="faint" style={{ fontSize: 12, marginTop: 1 }}>{it.s}</div>
              </div>
            </div>
          );
        })}
      </div>
    </Drawer>
  );
}

Object.assign(window, { Sidebar, Topbar, AIAssistant, NotifPanel });
