// desktop-app.jsx  admin app: login · dashboard · planner · team · structure

const { useState, useEffect, useRef } = React;

//  Nextcloud logo glyph 
function NextcloudGlyph() {
  return (
    <svg width="20" height="20" viewBox="0 0 256 256">
      <circle cx="128" cy="128" r="128" fill="#0082C9"/>
      <path fill="#fff" d="M128 64c-28.8 0-52.8 19.5-60.2 46H64c-19.9 0-36 16.1-36 36s16.1 36 36 36h128c19.9 0 36-16.1 36-36s-16.1-36-36-36h-3.8C180.8 83.5 156.8 64 128 64zm0 16c22.1 0 40.6 14.9 46.4 35.2l1.8 6.8H192c11.1 0 20 8.9 20 20s-8.9 20-20 20H64c-11.1 0-20-8.9-20-20s8.9-20 20-20h15.8l1.8-6.8C67.4 94.9 85.9 80 128 80z"/>
    </svg>
  );
}
function GoogleGlyph() {
  return (
    <svg width="20" height="20" viewBox="0 0 48 48">
      <path fill="#4285F4" d="M45.12 24.5c0-1.56-.14-3.06-.4-4.5H24v8.51h11.84c-.51 2.75-2.06 5.08-4.39 6.64v5.52h7.11c4.16-3.83 6.56-9.47 6.56-16.17z"/>
      <path fill="#34A853" d="M24 46c5.94 0 10.92-1.97 14.56-5.33l-7.11-5.52c-1.97 1.32-4.49 2.1-7.45 2.1-5.73 0-10.58-3.87-12.31-9.07H4.34v5.7C7.96 41.07 15.4 46 24 46z"/>
      <path fill="#FBBC04" d="M11.69 28.18c-.44-1.32-.69-2.73-.69-4.18s.25-2.86.69-4.18v-5.7H4.34A21.99 21.99 0 0 0 2 24c0 3.55.85 6.91 2.34 9.88l7.35-5.7z"/>
      <path fill="#EA4335" d="M24 9.75c3.23 0 6.13 1.11 8.41 3.29l6.31-6.31C34.91 3.16 29.93 1 24 1 15.4 1 7.96 5.93 4.34 13.12l7.35 5.7C13.42 13.62 18.27 9.75 24 9.75z"/>
    </svg>
  );
}

function TuLogoMark({ size = 28, light = false }) {
  const fg = light ? '#fff' : 'var(--primary)';
  const bg = light ? 'rgba(255,255,255,.18)' : 'var(--primary-soft)';
  return (
    <div style={{ width: size, height: size, borderRadius: size * 0.28, background: bg, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
      <svg viewBox="0 0 24 24" width={size * 0.7} height={size * 0.7} fill="none" stroke={fg} strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round">
        <path d="M7 4.5 L7 19.5"/>
        <path d="M16.5 5 L9.5 12"/>
        <path d="M9.5 12 L17 19.5"/>
        <circle cx="9.5" cy="12" r="1.6" fill={fg} stroke="none"/>
      </svg>
    </div>
  );
}

//  Desktop App Root 
function DesktopApp() {
  const ctx = useTurni();
  const [session, setSession] = useState(() => kairosReadDesktopSession());
  const [route, setRoute] = useState(() => kairosReadDesktopSession()?.user ? 'dashboard' : 'login');
  const user = session?.user || null;

  useEffect(() => {
    if (!user) return;
    if (!KAIROS_API) {
      ctx.refresh?.();
      return;
    }
    fetch(KAIROS_API + '/api/auth/session', { headers: kairosAuthHeaders() })
      .then(async r => {
        if (!r.ok) throw new Error('sessione scaduta');
        const data = await r.json();
        if (data.user) setSession(kairosSetDesktopSession(data.user, kairosDesktopToken()));
        ctx.refresh?.();
      })
      .catch(() => handleLogout());
  }, [user?.id]);

  const handleLogin = async (u, token) => {
    setSession(kairosSetDesktopSession(u, token));
    const s = await ctx.refresh?.();
    const freshStores = s?.stores || ctx.stores;
    const freshTeam = s?.team || ctx.team;
    const allIds = freshStores.map(st => st.id);
    let vis;
    if (!u || u.role === 'admin' || u.role === 'super_admin') vis = allIds;
    else if (u.role === 'capo') vis = freshStores.filter(st => (u.companyIds||[]).includes(st.companyId)).map(st => st.id);
    else vis = (u.storeIds||[]).filter(id => allIds.includes(id));
    const hasTeam = (id) => freshTeam.some(e => e.storeId === id);
    ctx.setCurrentStoreId(vis.find(id => hasTeam(id)) || vis[0] || null);
    setRoute('dashboard');
  };
  const handleLogout = () => {
    kairosLogoutDesktop();
    setSession(null);
    setRoute('login');
  };

  if (!user || route === 'login') {
    return <DesktopLogin onLogin={handleLogin} />;
  }
  return (
    <DesktopShell route={route} setRoute={setRoute} user={user} onLogout={handleLogout}>
      {route === 'dashboard'  && <DesktopDashboard user={user} goPlanner={() => setRoute('planner')} goStructure={() => setRoute('structure')} />}
      {route === 'planner'    && <DesktopPlanner user={user} />}
      {route === 'team'       && <DesktopTeam user={user} />}
      {route === 'structure'  && <DesktopStructure user={user} />}
    </DesktopShell>
  );
}

//  MAORI GROUP logo 
// Usa l'immagine reale /icons/maori-logo.png; se manca, fallback al wordmark disegnato.
function MaoriLogo({ width = 200 }) {
  const [imgOk, setImgOk] = useState(true);
  if (imgOk) {
    return (
      <img src="/icons/maori-logo.png" alt="MAORI GROUP" onError={() => setImgOk(false)}
        style={{ display: 'block', margin: '0 auto', width, maxWidth: '100%', height: 'auto' }}/>
    );
  }
  return (
    <div style={{ textAlign: 'center' }}>
      <svg width="120" height="64" viewBox="0 0 200 110" style={{ display: 'block', margin: '0 auto' }}>
        <defs>
          <linearGradient id="maoriFluke" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="#3b7fd6"/>
            <stop offset="55%" stopColor="#1f4e8c"/>
            <stop offset="100%" stopColor="#16243a"/>
          </linearGradient>
        </defs>
        <path d="M100 100 C78 78 60 50 20 18 C52 36 80 46 100 52 C120 46 148 36 180 18 C140 50 122 78 100 100 Z" fill="url(#maoriFluke)"/>
      </svg>
      <div style={{ fontFamily: 'Georgia, "Times New Roman", serif', fontSize: 30, letterSpacing: '.34em', color: '#1b1b1b', paddingLeft: '.34em', marginTop: 8, lineHeight: 1 }}>MAORI</div>
      <div style={{ height: 1, background: '#1b1b1b', width: 154, margin: '7px auto 6px' }}/>
      <div style={{ fontFamily: 'Georgia, "Times New Roman", serif', fontSize: 11, letterSpacing: '.5em', color: '#6b7280', paddingLeft: '.5em' }}>GROUP</div>
    </div>
  );
}

//  Login (MAORI GROUP - email + password)
function DesktopLogin({ onLogin }) {
  const [email, setEmail]       = useState('');
  const [password, setPassword] = useState('');
  const [showPw, setShowPw]     = useState(false);
  const [error, setError]       = useState('');
  const [busy, setBusy]         = useState(false);
  const [providers, setProviders] = useState({ google: false, nextcloud: false });

  useEffect(() => {
    fetch(KAIROS_API + '/api/auth/providers')
      .then(r => r.json())
      .then(setProviders)
      .catch(() => {});
  }, []);

  useEffect(() => {
    const hash = new URLSearchParams(location.hash.replace(/^#/, ''));
    const oauth = hash.get('oauth');
    const oauthError = hash.get('oauth_error');
    if (!oauth && !oauthError) return;
    history.replaceState(null, '', location.pathname + location.search);
    if (oauthError) {
      setError(oauthError);
      return;
    }
    try {
      const b64 = oauth.replace(/-/g, '+').replace(/_/g, '/');
      const payload = JSON.parse(atob(b64 + '='.repeat((4 - b64.length % 4) % 4)));
      if (payload?.user) onLogin(payload.user, payload.token);
    } catch {
      setError('Risposta OAuth non valida');
    }
  }, []);

  const canSubmit = email.trim() && password.trim() && !busy;
  const loginWithEmail = async () => {
    setError('');
    setBusy(true);
    try {
      const res = await fetch(KAIROS_API + '/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      });
      const data = await res.json().catch(() => null);
      if (!res.ok) throw new Error(data?.error || 'Accesso non riuscito');
      onLogin(data.user, data.token);
    } catch (e) {
      setError(e.message || 'Accesso non riuscito');
    }
    setBusy(false);
  };
  const submit = () => { if (canSubmit) loginWithEmail(); };
  const loginWithProvider = (provider) => {
    location.href = KAIROS_API + `/api/auth/oauth/${provider}/start?returnTo=desktop`;
  };

  const labelStyle = { display: 'block', fontSize: 13.5, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 8 };
  const iconLeft   = { position: 'absolute', left: 14, top: '50%', transform: 'translateY(-50%)', color: 'var(--ink-4)', display: 'flex', pointerEvents: 'none' };

  const lockIcon = <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>;
  const eyeIcon  = <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></svg>;
  const eyeOff   = <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l18 18"/><path d="M10.6 10.6a3 3 0 0 0 4.2 4.2"/><path d="M9.9 5.2A10.6 10.6 0 0 1 12 5c6.5 0 10 7 10 7a18 18 0 0 1-3.2 4.1M6.1 6.1A18 18 0 0 0 2 12s3.5 7 10 7a10.5 10.5 0 0 0 2.1-.2"/></svg>;

  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto', background: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '40px 24px', fontFamily: 'var(--font)' }}>
      <div style={{ width: '100%', maxWidth: 380 }}>
        <div style={{ marginBottom: 38 }}><MaoriLogo/></div>

        {/* Email */}
        <label style={labelStyle}>Email</label>
        <div style={{ position: 'relative', marginBottom: 20 }}>
          <span style={iconLeft}><TuIcon.user size={18}/></span>
          <input className="tu-input" type="email" autoComplete="username" placeholder="Inserisci la tua email"
            value={email} onChange={e => setEmail(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && submit()}
            style={{ height: 48, paddingLeft: 42 }}/>
        </div>

        {/* Password */}
        <label style={labelStyle}>Password</label>
        <div style={{ position: 'relative', marginBottom: 24 }}>
          <span style={iconLeft}>{lockIcon}</span>
          <input className="tu-input" type={showPw ? 'text' : 'password'} autoComplete="current-password" placeholder="Inserisci la tua password"
            value={password} onChange={e => setPassword(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && submit()}
            style={{ height: 48, paddingLeft: 42, paddingRight: 46 }}/>
          <button type="button" onClick={() => setShowPw(v => !v)} title={showPw ? 'Nascondi' : 'Mostra'}
            style={{ position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)', border: 0, background: 'transparent', color: 'var(--ink-4)', cursor: 'pointer', display: 'flex', padding: 4 }}>
            {showPw ? eyeOff : eyeIcon}
          </button>
        </div>

        {/* Submit */}
        <button onClick={submit} disabled={!canSubmit}
          style={{ width: '100%', height: 50, borderRadius: 12, border: 0, background: 'var(--primary)', color: '#fff', fontSize: 15, fontWeight: 700, cursor: canSubmit ? 'pointer' : 'not-allowed', opacity: canSubmit ? 1 : .55, boxShadow: '0 8px 18px var(--primary-glow)' }}>
          {busy ? 'Accesso...' : 'Accedi al Sistema'}
        </button>
        {/* Accesso unico tramite Portal SSO (portal.easytlc.it). Il portale rimanda a
            /desktop.html#oauth=<payload> e l'handler oauth qui sopra completa il login. */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '18px 0 14px' }}>
          <div style={{ flex: 1, height: 1, background: 'var(--line)' }}/>
          <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.08em', color: 'var(--ink-4)', textTransform: 'uppercase' }}>oppure</span>
          <div style={{ flex: 1, height: 1, background: 'var(--line)' }}/>
        </div>
        <button type="button" onClick={() => { location.href = 'https://portal.easytlc.it/access.php?system=turni'; }}
          title="Accedi con il Portal SSO Maori"
          style={{ width: '100%', height: 48, borderRadius: 12, border: '1px solid var(--line)', background: '#fff', color: 'var(--ink)', fontSize: 14, fontWeight: 800, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9 }}>
          <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#16a34a" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l7 3v5c0 4.6-3.1 8.2-7 10-3.9-1.8-7-5.4-7-10V6l7-3Z"/><path d="M9 12l2 2 4-4"/></svg>
          Accedi con SSO Maori
        </button>
        {error && (
          <div style={{ marginTop: 12, background: '#FBE0DD', color: '#9B2A21', borderRadius: 10, padding: '10px 12px', fontSize: 12.5, fontWeight: 700, lineHeight: 1.35 }}>
            {error}
          </div>
        )}

        {/* Footer */}
        <div style={{ textAlign: 'center', marginTop: 30, paddingTop: 18, borderTop: '1px solid var(--line)', fontSize: 12.5, color: 'var(--ink-4)' }}>
          Accesso riservato al personale autorizzato
        </div>
      </div>
    </div>
  );
}

//  Pending Approvals Modal (Super Admin only) 
function PendingApprovalsModal({ onClose }) {
  const ctx = useTurni();
  const [selectedRole, setSelectedRole] = useState({});
  const [busy, setBusy] = useState({});

  const roles = [
    { value: 'admin',   label: 'Amministrazione' },
    { value: 'capo',    label: 'Capocanali' },
    { value: 'manager', label: 'Store manager' },
  ];

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(31,27,23,.45)', backdropFilter: 'blur(6px)' }}
      onClick={onClose}>
      <div style={{ width: 560, background: 'var(--surface)', borderRadius: 24, padding: 32, boxShadow: '0 40px 80px rgba(0,0,0,.25)', position: 'relative' }}
        onClick={e => e.stopPropagation()}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
          <div>
            <div className="tu-tiny" style={{ marginBottom: 4 }}>Super Admin · Sicurezza</div>
            <div className="tu-h2">Richieste di accesso in attesa</div>
          </div>
          <button onClick={onClose} style={{ border: 0, background: 'var(--bg-2)', borderRadius: 10, width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
            <TuIcon.x size={16}/>
          </button>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {ctx.pendingApprovals.length === 0 && (
            <div style={{ textAlign: 'center', padding: 32, color: 'var(--ink-3)' }}>Nessuna richiesta in attesa </div>
          )}
          {ctx.pendingApprovals.map(pa => (
            <div key={pa.id} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: 16, background: 'var(--bg)', borderRadius: 14, border: '1px solid var(--line)' }}>
              <TuAvatar name={pa.name} size={42}/>
              <div style={{ flex: 1, lineHeight: 1.3 }}>
                <div style={{ fontWeight: 700, fontSize: 14 }}>{pa.name}</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{pa.email}</div>
                <div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 2, display: 'flex', gap: 8 }}>
                  <span style={{ background: pa.provider === 'google' ? '#E8F0FE' : '#E0F2FE', color: pa.provider === 'google' ? '#1967D2' : '#0369A1', padding: '2px 8px', borderRadius: 999, fontWeight: 700 }}>
                    {pa.provider === 'google' ? 'Google' : 'Nextcloud'}
                  </span>
                  <span>Richiesto: {new Date(pa.requestedAt).toLocaleDateString('it-IT')}</span>
                </div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <select value={selectedRole[pa.id] || 'manager'} onChange={e => setSelectedRole(r => ({ ...r, [pa.id]: e.target.value }))}
                  style={{ border: '1px solid var(--line)', borderRadius: 8, padding: '6px 10px', background: 'var(--surface)', fontSize: 12, fontWeight: 600, color: 'var(--ink)', cursor: 'pointer' }}>
                  {roles.map(r => <option key={r.value} value={r.value}>{r.label}</option>)}
                </select>
                <div style={{ display: 'flex', gap: 6 }}>
                  <button disabled={!!busy[pa.id]} onClick={async () => { setBusy(b => ({ ...b, [pa.id]: true })); await ctx.approvePendingUser(pa.id, selectedRole[pa.id] || 'manager').catch(() => {}); setBusy(b => ({ ...b, [pa.id]: false })); }} style={{
                    flex: 1, height: 32, borderRadius: 8, border: 'none', background: busy[pa.id] ? 'var(--line)' : 'var(--ok)', color: '#fff', fontWeight: 700, fontSize: 12, cursor: busy[pa.id] ? 'not-allowed' : 'pointer', opacity: busy[pa.id] ? .6 : 1,
                  }}>{busy[pa.id] ? '…' : 'Approva'}</button>
                  <button disabled={!!busy[pa.id]} onClick={async () => { setBusy(b => ({ ...b, [pa.id]: true })); await ctx.rejectPendingUser(pa.id).catch(() => {}); setBusy(b => ({ ...b, [pa.id]: false })); }} style={{
                    width: 32, height: 32, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--surface)', color: busy[pa.id] ? 'var(--ink-3)' : 'var(--danger)', fontWeight: 700, fontSize: 12, cursor: busy[pa.id] ? 'not-allowed' : 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}><TuIcon.x size={14}/></button>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

//  Shell with sidebar 
function DesktopShell({ route, setRoute, user, onLogout, children }) {
  const ctx = useTurni();

  const isAdmin = ctx.isAdminRole(user);
  const isSuperAdmin = ctx.isSuperAdminRole(user);
  const visibleStoreIds = ctx.visibleStoreIds(user);
  const editableStoreIds = ctx.editableStoreIds(user);
  const visibleStores = ctx.stores.filter(s => visibleStoreIds.includes(s.id));
  const navItems = [
    { id: 'dashboard', icon: TuIcon.home,     label: 'Dashboard' },
    { id: 'planner',   icon: TuIcon.cal,      label: 'Turni' },
    { id: 'team',      icon: TuIcon.users,    label: 'Personale' },
    { id: 'structure', icon: TuIcon.building, label: 'Società & Negozi' },
  ].filter(it => it.id !== 'structure' || ctx.canManageStructure(user));

  return (
    <div className="tu-app" style={{ width: '100%', height: '100%', display: 'flex', background: 'var(--bg)' }}>
      {/* Sidebar */}
      <aside style={{ width: 280, flexShrink: 0, background: 'var(--surface)', borderRight: '1px solid var(--line)', display: 'flex', flexDirection: 'column', padding: '20px 14px' }}>
        <div style={{ padding: '4px 6px 18px' }}>
          <MaoriLogo width={150}/>
        </div>

        {/* Stores column */}
        <div style={{ marginBottom: 16 }}>
          <div className="tu-tiny" style={{ padding: '0 6px 8px' }}>Negozi</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 250, overflowY: 'auto', paddingRight: 2 }}>
            {visibleStores.map(store => {
              const active = store.id === ctx.currentStoreId;
              const readOnly = !editableStoreIds.includes(store.id);
              const company = ctx.companies.find(c => c.id === store.companyId);
              return (
                <button key={store.id} onClick={() => ctx.setCurrentStoreId(store.id)}
                  title={`${store.name}${company ? ' - ' + company.name : ''}`}
                  style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '10px 11px', borderRadius: 12, border: `1px solid ${active ? 'var(--primary)' : 'var(--line)'}`, background: active ? 'var(--primary-soft)' : 'var(--bg-2)', color: active ? 'var(--primary-deep)' : 'var(--ink)', textAlign: 'left', cursor: 'pointer' }}>
                  <span style={{ width: 30, height: 30, borderRadius: 8, background: active ? 'var(--primary)' : 'var(--surface)', color: active ? '#fff' : 'var(--ink-3)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 900, flexShrink: 0 }}>
                    {store.short?.slice(0,2) || store.name?.slice(0,2) || '??'}
                  </span>
                  <span style={{ flex: 1, minWidth: 0, lineHeight: 1.15 }}>
                    <span style={{ display: 'block', fontSize: 12.5, fontWeight: 800, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{store.name}</span>
                    <span style={{ display: 'block', fontSize: 10.5, color: active ? 'var(--primary-deep)' : 'var(--ink-3)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{company?.name || store.city}</span>
                  </span>
                  {readOnly && <span style={{ fontSize: 9.5, fontWeight: 800, color: active ? 'var(--primary-deep)' : 'var(--ink-4)', background: active ? 'rgba(255,255,255,.55)' : 'var(--surface)', padding: '2px 6px', borderRadius: 999, flexShrink: 0 }}>solo</span>}
                </button>
              );
            })}
            {!visibleStores.length && (
              <div style={{ padding: '12px 10px', border: '1px dashed var(--line)', borderRadius: 12, color: 'var(--ink-3)', fontSize: 12.5 }}>Nessun negozio visibile.</div>
            )}
          </div>
        </div>

        <div className="tu-tiny" style={{ padding: '6px 6px' }}>Lavoro</div>
        <nav style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
          {navItems.map(it => {
            const active = it.id === route;
            return (
              <button key={it.id} onClick={() => setRoute(it.id)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '9px 12px', borderRadius: 10, border: 0, background: active ? 'var(--primary-soft)' : 'transparent', color: active ? 'var(--primary-deep)' : 'var(--ink-2)', fontWeight: active ? 700 : 600, fontSize: 13.5, textAlign: 'left' }}>
                <span style={{ display: 'inline-flex', width: 18 }}><it.icon/></span>
                <span style={{ flex: 1 }}>{it.label}</span>
              </button>
            );
          })}
        </nav>

        <div style={{ marginTop: 'auto', paddingTop: 16 }}>
          {isSuperAdmin && ctx.pendingApprovals.length > 0 && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', borderRadius: 12, background: '#FBE0DD', border: '1px solid #F5B8B0', marginBottom: 10 }}>
              <TuIcon.shield size={16} style={{ color: 'var(--danger)' }}/>
              <div style={{ flex: 1, fontSize: 12, fontWeight: 600, color: '#9B2A21' }}>{ctx.pendingApprovals.length} accessi in attesa</div>
            </div>
          )}
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: 10, border: '1px solid var(--line)', borderRadius: 12, background: 'var(--bg)' }}>
            <TuAvatar name={user?.name || 'Admin'} size={32}/>
            <div style={{ flex: 1, lineHeight: 1.15 }}>
              <div style={{ fontSize: 12.5, fontWeight: 700 }}>{user?.name}</div>
              <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{user?.label}</div>
            </div>
            <button onClick={onLogout} title="Esci" style={{ border: 0, background: 'transparent', padding: 6, color: 'var(--ink-3)', display: 'flex', borderRadius: 8, cursor: 'pointer' }}><TuIcon.logout size={16}/></button>
          </div>
        </div>
      </aside>

      <main style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
        {children}
      </main>
    </div>
  );
}

//  Store Switcher Dropdown 
function StoreSwitcherDropdown({ onClose, user }) {
  const ctx = useTurni();
  const ref = useRef(null);

  useEffect(() => {
    const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    document.addEventListener('pointerdown', handler, true);
    return () => document.removeEventListener('pointerdown', handler, true);
  }, []);

  const visible  = ctx.visibleStoreIds(user);
  const editable = ctx.editableStoreIds(user);

  return (
    <div ref={ref} style={{ position: 'absolute', top: 'calc(100% + 8px)', left: 0, right: 0, background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 16, boxShadow: '0 12px 40px rgba(0,0,0,.15)', zIndex: 20, overflow: 'hidden', maxHeight: 320, overflowY: 'auto' }}>
      {ctx.companies.map(co => {
        const coStores = ctx.stores.filter(s => s.companyId === co.id && visible.includes(s.id));
        if (coStores.length === 0) return null;
        return (
          <div key={co.id}>
            <div style={{ padding: '10px 14px 4px', fontSize: 10.5, fontWeight: 700, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '.08em' }}>{co.name}</div>
            {coStores.map(s => {
              const readOnly = !editable.includes(s.id);
              return (
                <button key={s.id} onClick={() => { ctx.setCurrentStoreId(s.id); onClose(); }} style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 14px', border: 0, background: s.id === ctx.currentStoreId ? 'var(--primary-soft)' : 'transparent', color: s.id === ctx.currentStoreId ? 'var(--primary-deep)' : 'var(--ink)', fontWeight: s.id === ctx.currentStoreId ? 700 : 500, fontSize: 13, cursor: 'pointer', textAlign: 'left' }}>
                  <span style={{ width: 22, height: 22, borderRadius: 6, background: s.id === ctx.currentStoreId ? 'var(--primary)' : 'var(--bg-2)', color: s.id === ctx.currentStoreId ? '#fff' : 'var(--ink-3)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 9, fontWeight: 800, flexShrink: 0 }}>{s.short?.slice(0,2)}</span>
                  {s.name}
                  {readOnly && <span style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--ink-4)', background: 'var(--bg-2)', padding: '1px 6px', borderRadius: 999, marginLeft: 6 }}>sola lettura</span>}
                  {s.id === ctx.currentStoreId && <span style={{ marginLeft: 'auto' }}><TuIcon.check size={14}/></span>}
                </button>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}

//  Topbar 
function DesktopTopbar({ title, subtitle, actions }) {
  return (
    <header style={{ minHeight: 82, padding: '12px 28px', display: 'flex', alignItems: 'center', gap: 14, borderBottom: '1px solid var(--line)', background: 'var(--surface)' }}>
      <div style={{ flex: 1, minWidth: 180 }}>
        <div style={{ fontSize: 20, fontWeight: 800, letterSpacing: '-.015em', lineHeight: 1.08 }}>{title}</div>
        {subtitle && <div style={{ fontSize: 12.5, color: 'var(--ink-3)', marginTop: 2 }}>{subtitle}</div>}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 999, padding: '0 14px', height: 38, width: 280, maxWidth: '32vw', color: 'var(--ink-3)' }}>
        <TuIcon.search size={16}/>
        <input placeholder="Cerca persone, turni..." style={{ border: 0, background: 'transparent', flex: 1, outline: 'none', font: 'inherit', fontSize: 13, color: 'var(--ink)' }}/>
      </div>
      {actions}
      <button className="tu-btn tu-btn-icon tu-btn-ghost" title="Notifiche"><TuIcon.bell size={17}/></button>
    </header>
  );
}

Object.assign(window, { DesktopApp, DesktopTopbar, TuLogoMark, GoogleGlyph, NextcloudGlyph, PendingApprovalsModal, StoreSwitcherDropdown });
