// app.jsx — functional D&D Energy ERP entry.
// Hash router + auth gate. Session is an httpOnly cookie managed by the server;
// the browser just asks /api/auth/me whether it's valid.

const IDLE_MS = 15 * 60 * 1000; // local heartbeat — server is authoritative

function getRoute() {
  const h = window.location.hash.replace(/^#\/?/, '');
  // Strip query string — "order?id=18186" → "order"
  return h.split('?')[0] || 'dashboard';
}
function setRoute(r) { window.location.hash = '#/' + r; }

function renderScreen(route) {
  switch (route) {
    case 'dashboard':   return <Dashboard/>;
    case 'orders':      return <OrdersList/>;
    case 'order':       return <OrderDetail/>;
    case 'products':    return <Products/>;
    case 'ai':          return <AiAssistant/>;
    case 'pricing':     return <IndividualPricing/>;
    case 'b2b':         return <B2BApprovals/>;
    case 'datasheets':  return <Datasheets/>;
    case 'gallery':     return <Realizations/>;
    case 'calendar':    return <CalendarLeave/>;
    case 'servis':      return <TechnicianServis/>;
    case 'pickup':      return <PickupCalendar/>;
    case 'forms':       return <FormsScreen/>;
    // Sidebar "ERP Používatelia" (admin) → internal team.
    // Sidebar "Zákazníci" (work) → WooCommerce customers list, detail under /customer?id=…
    case 'users':       return <UsersPermissions/>;
    case 'customers':   return <UsersList/>;
    case 'customer':    return <UserDetail/>;
    case 'user':        return <UserDetail/>;   // legacy alias
    case 'modules':     return <ModuleManager/>;
    case 'settings':    return <Settings2FA/>;
    case 'launcher':    return <AppLauncher/>;
    case 'integrations':return <IntegrationsScreen/>;
    case 'terminal':    return <AdminTerminal/>;
    default:            return <NotFound route={route}/>;
  }
}

function NotFound({ route }) {
  return (
    <AppShell active="dashboard" crumbs={['Domov', '404']}>
      <div className="page-head">
        <div>
          <h1>Stránka nenájdená</h1>
          <p>Route <code>#/{route}</code> neexistuje.</p>
        </div>
        <div className="page-head-actions">
          <a href="#/dashboard" className="btn btn-primary">Na prehľad</a>
        </div>
      </div>
    </AppShell>
  );
}

// ── Force password change (first-login / reset) ──
function ForcePasswordChange({ session, onDone }) {
  const [current, setCurrent] = React.useState('');
  const [next, setNext] = React.useState('');
  const [confirm, setConfirm] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  async function submit(e) {
    e.preventDefault();
    setErr('');
    if (next.length < 12) return setErr('Nové heslo musí mať aspoň 12 znakov.');
    if (next !== confirm) return setErr('Potvrdenie sa nezhoduje.');
    setBusy(true);
    const r = await API.changePassword(current, next);
    setBusy(false);
    if (r.ok) onDone();
    else setErr(r.body.error === 'wrong_password' ? 'Aktuálne (dočasné) heslo je nesprávne.' : r.body.message || 'Chyba.');
  }

  return (
    <div className="auth-wrap">
      <div className="auth-left">
        <div className="auth-logo"><BrandBadge size={56}/><div className="auth-logo-text">D&amp;D Energy<small>Interný systém</small></div></div>
        <div className="auth-tagline">
          <h2>Zmeňte si <span>heslo.</span></h2>
          <p>Používate dočasné heslo pridelené administrátorom. Pre ďalšiu prácu si musíte zvoliť vlastné.</p>
        </div>
      </div>
      <form className="auth-right" onSubmit={submit}>
        <h3>Povinná zmena hesla</h3>
        <div className="sub">Prihlásený ako <b>{(session.user || {}).email}</b></div>
        {err && <div className="auth-alert" role="alert"><span>{err}</span></div>}
        <div className="auth-form">
          <div className="field">
            <label>Aktuálne (dočasné) heslo</label>
            <input className="input" type="password" value={current} onChange={e => setCurrent(e.target.value)} autoComplete="current-password" required autoFocus/>
          </div>
          <div className="field">
            <label>Nové heslo (min. 12 znakov)</label>
            <input className="input" type="password" value={next} onChange={e => setNext(e.target.value)} autoComplete="new-password" minLength={12} required/>
          </div>
          <div className="field">
            <label>Potvrdiť nové heslo</label>
            <input className="input" type="password" value={confirm} onChange={e => setConfirm(e.target.value)} autoComplete="new-password" required/>
          </div>
          <button className="btn btn-primary btn-lg btn-block" type="submit" disabled={busy}>
            {busy ? 'Ukladám…' : 'Nastaviť heslo a pokračovať'}
          </button>
        </div>
      </form>
    </div>
  );
}

// ── Force 2FA setup — admin policy requires TOTP for all users ──
function Force2FASetup({ session, onDone, onLogout }) {
  const [setupData, setSetupData] = React.useState(null);
  const [code, setCode] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  async function start() {
    setBusy(true); setErr('');
    const r = await API.twofaSetup();
    setBusy(false);
    if (r.ok) setSetupData(r.body);
    else setErr(r.body.message || 'Chyba.');
  }
  React.useEffect(() => { start(); /* eslint-disable-next-line */ }, []);

  async function confirm() {
    setBusy(true); setErr('');
    const r = await API.twofaEnable(code);
    setBusy(false);
    if (r.ok) onDone();
    else setErr(r.body.error === 'invalid_code' ? 'Zlý kód.' : r.body.message || 'Chyba.');
  }

  return (
    <div className="auth-wrap">
      <div className="auth-left">
        <div className="auth-logo"><BrandBadge size={56}/><div className="auth-logo-text">D&amp;D Energy<small>Interný systém</small></div></div>
        <div className="auth-tagline">
          <h2>Nastavte <span>2FA.</span></h2>
          <p>Pre prístup do ERP je povinné dvojfaktorové overenie. Budete ho potvrdzovať každý týždeň — od pondelka do nedele.</p>
        </div>
      </div>
      <div className="auth-right" style={{width: 520}}>
        <div className="auth-badge"><Ico.shield/></div>
        <h3>Nastavenie 2FA</h3>
        <div className="sub">Prihlásený ako <b>{(session.user || {}).email}</b> — pokračovať bez nastavenia 2FA sa nedá.</div>

        {err && <div className="auth-alert" role="alert"><span>{err}</span></div>}

        {!setupData && <div className="muted" style={{padding:20}}>Generujem secret…</div>}

        {setupData && (
          <div className="vstack" style={{gap:12, marginTop:10}}>
            <div style={{textAlign:'center'}}>
              <div style={{display:'inline-block', padding:6, border:'1px solid var(--border)', borderRadius:8, background:'#fff'}}>
                <img src={setupData.qr_data_url} alt="2FA QR" style={{display:'block', width:220, height:220}}/>
              </div>
            </div>
            <div className="field">
              <label>Secret (ak sken nefunguje)</label>
              <div className="hstack">
                <input className="input mono" value={setupData.secret} readOnly style={{flex:1, fontSize:12.5}}/>
                <button type="button" className="btn btn-sm" onClick={() => navigator.clipboard && navigator.clipboard.writeText(setupData.secret)}>Kopírovať</button>
              </div>
            </div>
            <div className="field">
              <label>6-ciferný kód z aplikácie</label>
              <input
                className="input mono"
                inputMode="numeric"
                maxLength={6}
                value={code}
                onChange={e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
                placeholder="123456"
                style={{fontSize:20, letterSpacing:5, textAlign:'center'}}
                autoFocus
              />
            </div>
            <button className="btn btn-primary btn-lg btn-block" onClick={confirm} disabled={busy || code.length !== 6}>
              {busy ? 'Overujem…' : 'Potvrdiť a pokračovať'}
            </button>
            <div style={{textAlign:'center', fontSize:12}}>
              <a onClick={onLogout} style={{color:'var(--ink-500)', cursor:'pointer'}}>Odhlásiť sa</a>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function BootSplash() {
  return (
    <div style={{
      position:'fixed', inset:0, display:'flex', alignItems:'center', justifyContent:'center',
      background:'linear-gradient(135deg,#0e2744,#133258 60%,#23507f)', color:'#e6eef7', fontFamily:'Georama, system-ui'
    }}>
      <div style={{textAlign:'center'}}>
        <div className="sb-logo-mark" style={{width:56, height:56, margin:'0 auto 14px'}}/>
        <div style={{fontWeight:700, fontSize:18}}>D&amp;D Energy ERP</div>
        <div style={{fontSize:11, color:'#a6c0df', marginTop:4, letterSpacing:'0.18em', textTransform:'uppercase'}}>Overujem reláciu…</div>
      </div>
    </div>
  );
}

// Applies favicon, document title and exposes branding globally for Logo to read.
function applyBranding(b) {
  if (!b) return;
  window.currentBranding = b;

  // Favicon — replace or insert <link rel="icon">
  if (b.favicon_url) {
    let link = document.querySelector('link[rel="icon"], link[rel="shortcut icon"]');
    if (!link) { link = document.createElement('link'); link.rel = 'icon'; document.head.appendChild(link); }
    link.href = b.favicon_url + '?v=' + Date.now();
  }
  // Title — "<app_name> ERP"
  if (b.app_name && !document.title.startsWith(b.app_name)) {
    document.title = b.app_name + ' · ERP';
  }
}

function App() {
  const [booting, setBooting] = React.useState(true);
  const [session, setSession] = React.useState(null);
  const [pending2FA, setPending2FA] = React.useState(null);
  const [route, setRouteState] = React.useState(getRoute());

  // Load branding on first mount (public endpoint — works even on login screen).
  React.useEffect(() => {
    fetch('/api/crm-settings/public').then(r => r.json()).then(j => {
      if (j && j.ok) applyBranding(j.branding);
    }).catch(() => {});
    const onChange = (e) => applyBranding(e.detail || (window.currentBranding || {}));
    window.addEventListener('branding:changed', onChange);
    return () => window.removeEventListener('branding:changed', onChange);
  }, []);

  React.useEffect(() => {
    const onHash = () => setRouteState(getRoute());
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  // On mount: check session via the server
  React.useEffect(() => {
    let alive = true;
    (async () => {
      const me = await API.me();
      if (!alive) return;
      if (me) setSession(me);
      setBooting(false);
    })();
    return () => { alive = false; };
  }, []);

  // Periodic revalidation — catches server-side logout / session expiry / perm changes
  React.useEffect(() => {
    if (!session) return;
    const id = setInterval(async () => {
      const me = await API.me();
      if (!me) setSession(null); else setSession(me);
    }, 60_000);
    return () => clearInterval(id);
  }, [session]);

  // Cross-tab logout
  React.useEffect(() => {
    const onVis = () => {
      if (document.visibilityState === 'visible') {
        API.me().then(me => {
          if (!me && session) setSession(null);
          else if (me) setSession(me);
        });
      }
    };
    document.addEventListener('visibilitychange', onVis);
    return () => document.removeEventListener('visibilitychange', onVis);
  }, [session]);

  // Live refresh when admin toggles a module — Sidebar rebuilds from new session.modules.
  React.useEffect(() => {
    const onChange = async () => {
      const me = await API.me();
      if (me) setSession(me);
    };
    window.addEventListener('dd-modules-changed', onChange);
    window.addEventListener('dd-session-changed', onChange);
    return () => {
      window.removeEventListener('dd-modules-changed', onChange);
      window.removeEventListener('dd-session-changed', onChange);
    };
  }, []);

  async function handleLoggedIn(_user) {
    // After login, re-fetch /me so we also get effective permissions + modules.
    const me = await API.me();
    if (me) setSession(me);
    const target = sessionStorage.getItem('dd_post_login') || 'dashboard';
    sessionStorage.removeItem('dd_post_login');
    setRoute(target);
  }
  function handleNeed2FA(ctx) {
    setPending2FA(ctx);
    setRoute('2fa');
  }
  function handle2FAVerified(user) {
    setPending2FA(null);
    handleLoggedIn(user);
  }
  async function handleLogout() {
    try { await API.logout(); } catch {}
    setSession(null);
    setPending2FA(null);
    setRoute('login');
  }

  if (booting) return <BootSplash/>;

  if (!session) {
    if (route === '2fa' && pending2FA) {
      return <TwoFactorScreen
        onVerified={handle2FAVerified}
        onBack={() => { setPending2FA(null); setRoute('login'); }}
        pendingUser={pending2FA}/>;
    }
    if (route && route !== 'login' && route !== '2fa') {
      try { sessionStorage.setItem('dd_post_login', route); } catch {}
    }
    return <LoginScreen onLoggedIn={handleLoggedIn} onNeed2FA={handleNeed2FA}/>;
  }

  // Policy gates (enforced after login)
  const policy = session.policy || {};
  if (policy.must_change_password) {
    return <ForcePasswordChange session={session} onDone={async () => {
      const me = await API.me();
      if (me) setSession(me);
    }}/>;
  }
  if (policy.must_setup_2fa) {
    return <Force2FASetup
      session={session}
      onDone={async () => {
        const me = await API.me();
        if (me) setSession(me);
      }}
      onLogout={handleLogout}
    />;
  }

  return <AppRootShell session={session} route={route} onLogout={handleLogout}/>;
}

function AppRootShell({ session, route, onLogout }) {
  // Expose session globally so individual screens can read permissions / current user
  // without having to wire props through AppShell.
  window.currentSession = session;
  if (session && session.branding) applyBranding(session.branding);
  window.hasPerm = (p) => {
    const perms = session && session.permissions;
    if (!perms) return false;
    if (perms['*'] === true) return true;
    return perms[p] === true;
  };

  React.useEffect(() => {
    const root = document.getElementById('root');
    if (!root) return;
    const handler = (e) => {
      const a = e.target.closest('.sidebar a');
      const logoutBtn = e.target.closest('.sb-user svg');
      if (a) {
        e.preventDefault();
        const label = (a.querySelector('span')?.textContent || '').trim();
        const map = {
          'Prehľad': 'dashboard',
          'Objednávky': 'orders',
          'Produkty': 'products',
          'Individ. ceny': 'pricing',
          'B2B schvaľ.': 'b2b',
          'Datasheety': 'datasheets',
          'Realizácie': 'gallery',
          'AI asistent': 'ai',
          'Kalendár & dovolenky': 'calendar',
          'Osobný odber': 'pickup',
          'Formuláre': 'forms',
          'Zákazníci': 'customers',
          'ERP Používatelia': 'users',
          'Používatelia': 'users',
          'Moduly': 'modules',
          'Integrácie': 'integrations',
          'Terminál': 'terminal',
          'Nastavenia': 'settings',
        };
        const target = map[label];
        if (target) {
          setRoute(target);
          document.body.classList.remove('sidebar-open');  // auto-close mobile drawer
        }
      } else if (logoutBtn && logoutBtn.closest('.sb-user')) {
        e.preventDefault();
        if (confirm('Naozaj sa chcete odhlásiť?')) onLogout();
      }
    };
    root.addEventListener('click', handler);
    return () => root.removeEventListener('click', handler);
  }, [onLogout]);

  // Mobile drawer: close on backdrop tap + ESC. Uses body::before as overlay,
  // so we attach a capture click handler on <body> and close if the tap wasn't
  // on .sidebar itself or on the hamburger.
  React.useEffect(() => {
    function onBodyClick(e) {
      if (!document.body.classList.contains('sidebar-open')) return;
      if (e.target.closest('.sidebar')) return;
      if (e.target.closest('.topbar-menu-btn')) return;
      // Tap was outside → close
      document.body.classList.remove('sidebar-open');
    }
    function onKey(e) {
      if (e.key === 'Escape') document.body.classList.remove('sidebar-open');
    }
    document.addEventListener('click', onBodyClick, true);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('click', onBodyClick, true);
      document.removeEventListener('keydown', onKey);
    };
  }, []);

  // Inject current user into the sidebar on every render
  React.useEffect(() => {
    const u = session.user || session;
    const name = document.querySelector('.sb-user-name');
    const role = document.querySelector('.sb-user-role');
    const av   = document.querySelector('.sb-avatar');
    if (name) name.textContent = u.name;
    if (role) role.textContent = u.role_label || (u.role === 'admin' ? 'Administrátor' : (u.role || 'Používateľ'));
    if (av)   av.textContent = (u.name || '?').split(/\s+/).map(p => p[0]).join('').slice(0, 2).toUpperCase();
  });

  return (
    <>
      {renderScreen(route)}
      {typeof FloatingAiAssistant !== 'undefined' && <FloatingAiAssistant/>}
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
