// Login + 2FA screens — functional with client-side validation,
// lockout after failed attempts, caps-lock detection, show/hide password,
// honeypot, 2FA with auto-advance/paste, resend cooldown, backup code mode.
//
// Security note (for production wiring):
//   - Hash passwords server-side (argon2id / bcrypt) — never store or compare plaintext.
//   - Keep the session token in an httpOnly, Secure, SameSite=Lax cookie, not in JS storage.
//   - Enforce rate-limiting + lockout server-side; client-side is only UX sugar.
//   - Validate TOTP codes server-side with a ±1 window; bind "remember device" to a signed token.
//   - Serve only over HTTPS + HSTS; set CSP, X-Frame-Options, Referrer-Policy.

// Extra icons used by these screens (defined locally so we don't need to touch shared.jsx)
const AuthIco = {
  eye: (p={}) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>,
  eyeOff: (p={}) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9.88 9.88a3 3 0 1 0 4.24 4.24"/><path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61"/><line x1="2" x2="22" y1="2" y2="22"/></svg>,
  alert: (p={}) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>,
  loader: (p={}) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>,
};

// ───── helpers ─────
const LOCK_KEY = 'dd_auth_lock';
const MAX_ATTEMPTS = 5;
const LOCK_MS = 60_000;

function getLock() {
  try {
    const raw = localStorage.getItem(LOCK_KEY);
    if (!raw) return { count: 0, until: 0 };
    const parsed = JSON.parse(raw);
    if (parsed.until && parsed.until < Date.now()) {
      localStorage.removeItem(LOCK_KEY);
      return { count: 0, until: 0 };
    }
    return parsed;
  } catch { return { count: 0, until: 0 }; }
}
function setLock(count, until) {
  try { localStorage.setItem(LOCK_KEY, JSON.stringify({ count, until })); } catch {}
}
function clearLock() { try { localStorage.removeItem(LOCK_KEY); } catch {} }

function isValidEmail(s) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(s.trim());
}

// API client — hits the Express backend (same origin).
// Session is in an httpOnly cookie; requests just need credentials: 'same-origin'.
async function apiFetch(path, opts = {}) {
  const r = await fetch(path, {
    credentials: 'same-origin',
    headers: opts.body ? { 'Content-Type': 'application/json' } : {},
    ...opts,
    body: opts.body ? JSON.stringify(opts.body) : undefined,
  });
  const body = await r.json().catch(() => ({}));
  return { status: r.status, ok: r.ok, body };
}

const API = {
  // ── auth ──
  async login(email, password, remember) {
    return apiFetch('/api/auth/login', { method: 'POST', body: { email, password, remember } });
  },
  async twofa(code) {
    return apiFetch('/api/auth/2fa', { method: 'POST', body: { code } });
  },
  async me() {
    const r = await apiFetch('/api/auth/me');
    return r.ok ? r.body : null;   // full { user, permissions, modules } or null
  },
  async logout() { await apiFetch('/api/auth/logout', { method: 'POST' }); },
  async changePassword(currentPassword, newPassword) {
    return apiFetch('/api/auth/change-password', { method: 'POST', body: { currentPassword, newPassword } });
  },
  async updateProfile(payload)        { return apiFetch('/api/auth/profile', { method: 'PATCH', body: payload }); },
  async twofaStatus()                 { return apiFetch('/api/auth/2fa/status'); },
  async twofaSetup()                  { return apiFetch('/api/auth/2fa/setup', { method: 'POST' }); },
  async twofaEnable(code)             { return apiFetch('/api/auth/2fa/enable', { method: 'POST', body: { code } }); },
  async twofaDisable(password, code)  { return apiFetch('/api/auth/2fa/disable', { method: 'POST', body: { password, code } }); },
  async getWpSettings()               { return apiFetch('/api/wp-settings'); },
  async saveWpSettings(payload)       { return apiFetch('/api/wp-settings', { method: 'PATCH', body: payload }); },

  // ── users ──
  async listUsers()                   { return (await apiFetch('/api/users')).body.users || []; },
  async createUser(payload)           { return apiFetch('/api/users', { method: 'POST', body: payload }); },
  async updateUser(id, payload)       { return apiFetch(`/api/users/${id}`, { method: 'PATCH', body: payload }); },
  async deleteUser(id)                { return apiFetch(`/api/users/${id}`, { method: 'DELETE' }); },
  async resetPassword(id)             { return apiFetch(`/api/users/${id}/reset-password`, { method: 'POST' }); },
  async getUserPermissions(id)        { return (await apiFetch(`/api/users/${id}/permissions`)).body; },
  async setUserPermissionOverrides(id, overrides) {
    return apiFetch(`/api/users/${id}/permissions`, { method: 'PATCH', body: { overrides } });
  },

  // ── roles ──
  async listRoles()                   { return (await apiFetch('/api/roles')).body.roles || []; },
  async createRole(payload)           { return apiFetch('/api/roles', { method: 'POST', body: payload }); },
  async updateRole(slug, payload)     { return apiFetch(`/api/roles/${slug}`, { method: 'PATCH', body: payload }); },
  async deleteRole(slug)              { return apiFetch(`/api/roles/${slug}`, { method: 'DELETE' }); },

  // ── modules ──
  async listModules()                 { return (await apiFetch('/api/modules')).body.modules || []; },
  async toggleModule(slug, enabled)   { return apiFetch(`/api/modules/${slug}`, { method: 'PATCH', body: { is_enabled: enabled } }); },

  // ── dashboard / WooCommerce data ──
  async dashboardSummary()            { return apiFetch('/api/dashboard/summary'); },
  async listOrders(params = {})       {
    const q = new URLSearchParams(params).toString();
    return apiFetch('/api/orders' + (q ? '?' + q : ''));
  },
  async getOrder(id)                  { return apiFetch('/api/orders/' + id); },
  async updateOrder(id, payload)      { return apiFetch('/api/orders/' + id, { method: 'PATCH', body: payload }); },
  async listProducts(params = {})     {
    const q = new URLSearchParams(params).toString();
    return apiFetch('/api/products' + (q ? '?' + q : ''));
  },
  async getProduct(id)                { return apiFetch('/api/products/' + id); },
  async listProductCategories()       { return apiFetch('/api/products/categories'); },
  async createProductCategory(payload){ return apiFetch('/api/products/categories', { method: 'POST', body: payload }); },
  async createProduct(payload)        { return apiFetch('/api/products', { method: 'POST', body: payload }); },
  async uploadMedia(file) {
    const fd = new FormData();
    fd.append('file', file);
    const r = await fetch('/api/media/upload', { method: 'POST', credentials: 'same-origin', body: fd });
    const body = await r.json().catch(() => ({}));
    return { status: r.status, ok: r.ok, body };
  },
  async updateProduct(id, payload)    { return apiFetch('/api/products/' + id, { method: 'PATCH', body: payload }); },
  async deleteProduct(id, force=false){ return apiFetch('/api/products/' + id + '?force=' + force, { method: 'DELETE' }); },
  async listCustomers(params = {})    {
    const q = new URLSearchParams(params).toString();
    return apiFetch('/api/customers' + (q ? '?' + q : ''));
  },
  async getCustomer(id)               { return apiFetch('/api/customers/' + id); },
  async updateCustomer(id, payload)   { return apiFetch('/api/customers/' + id, { method: 'PATCH', body: payload }); },
  async setCustomerPassword(id, password) {
    return apiFetch('/api/customers/' + id + '/set-password', { method: 'POST', body: password ? { password } : {} });
  },
  async sendCustomerResetEmail(id)    { return apiFetch('/api/customers/' + id + '/send-reset', { method: 'POST' }); },

  // ── AI ──
  async aiChat(payload)               { return apiFetch('/api/ai/chat', { method: 'POST', body: payload }); },
  async aiPickModel(prompt, opts={})  { return apiFetch('/api/ai/pick-model', { method: 'POST', body: { prompt, ...opts } }); },
  async aiListModels()                { return apiFetch('/api/ai/models'); },

  // ── B2B approvals (via WP bridge) ──
  async listB2BPending()              { return apiFetch('/api/b2b/pending'); },
  async decideB2B(userId, decision, note = '') {
    return apiFetch(`/api/b2b/decide/${userId}`, { method: 'POST', body: { decision, note } });
  },

  // ── Realizations (via WP bridge) ──
  async listRealizations(typ = '')    {
    return apiFetch('/api/realizations' + (typ ? '?typ=' + encodeURIComponent(typ) : ''));
  },
  async getRealization(id)            { return apiFetch('/api/realizations/' + id); },
  async createRealization(payload)    { return apiFetch('/api/realizations', { method: 'POST', body: payload }); },
  async updateRealization(id, payload){ return apiFetch('/api/realizations/' + id, { method: 'PATCH', body: payload }); },
  async deleteRealization(id)         { return apiFetch('/api/realizations/' + id, { method: 'DELETE' }); },
  async uploadRealizationImages(id, files) {
    const fd = new FormData();
    for (const f of files) fd.append('files', f);
    const r = await fetch(`/api/realizations/${id}/images`, { method: 'POST', credentials: 'same-origin', body: fd });
    const body = await r.json().catch(() => ({}));
    return { status: r.status, ok: r.ok, body };
  },
  async deleteRealizationImage(realizationId, imgId) {
    return apiFetch(`/api/realizations/${realizationId}/images/${imgId}`, { method: 'DELETE' });
  },

  // ── Datasheets (via WP bridge) ──
  async listDatasheets(productId = null) {
    return apiFetch('/api/datasheets' + (productId ? '?product_id=' + encodeURIComponent(productId) : ''));
  },
  async uploadDatasheet({ file, title, category, product_id }) {
    const fd = new FormData();
    fd.append('file', file);
    fd.append('title', title);
    fd.append('category', category || 'other');
    fd.append('product_id', product_id);
    const r = await fetch('/api/datasheets', { method: 'POST', credentials: 'same-origin', body: fd });
    const body = await r.json().catch(() => ({}));
    return { status: r.status, ok: r.ok, body };
  },
  async updateDatasheet(id, payload) { return apiFetch('/api/datasheets/' + id, { method: 'PATCH', body: payload }); },
  async deleteDatasheet(id)          { return apiFetch('/api/datasheets/' + id, { method: 'DELETE' }); },

  // ── Individual prices per customer (via WP bridge) ──
  async listCustomersWithPrices()   { return apiFetch('/api/individual-prices'); },
  async getIndividualPrices(userId) { return apiFetch('/api/individual-prices/' + userId); },
  async setIndividualPrices(userId, prices, deleteProductIds = []) {
    return apiFetch('/api/individual-prices/' + userId, {
      method: 'PATCH',
      body: { prices, delete_product_ids: deleteProductIds },
    });
  },
};

// ───── Login ─────
function LoginScreen({ onLoggedIn, onNeed2FA } = {}) {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const [showPass, setShowPass] = React.useState(false);
  const [remember, setRemember] = React.useState(true);
  const [trap, setTrap] = React.useState('');  // honeypot
  const [caps, setCaps] = React.useState(false);
  const [errors, setErrors] = React.useState({});
  const [globalErr, setGlobalErr] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [lock, setLockState] = React.useState(() => getLock());
  const [tick, setTick] = React.useState(0);
  const emailRef = React.useRef(null);

  // Focus email on mount
  React.useEffect(() => { emailRef.current && emailRef.current.focus(); }, []);

  // Countdown tick while locked
  React.useEffect(() => {
    if (!lock.until || lock.until < Date.now()) return;
    const id = setInterval(() => {
      setTick(t => t + 1);
      if (Date.now() >= lock.until) { clearLock(); setLockState({ count: 0, until: 0 }); }
    }, 500);
    return () => clearInterval(id);
  }, [lock.until]);

  const locked = Boolean(lock.until) && lock.until > Date.now();
  const secondsLeft = locked ? Math.ceil((lock.until - Date.now()) / 1000) : 0;

  function handleKey(e) {
    if (typeof e.getModifierState === 'function') setCaps(e.getModifierState('CapsLock'));
  }

  function validate() {
    const next = {};
    if (!email.trim()) next.email = 'Zadajte e-mail.';
    else if (!isValidEmail(email)) next.email = 'Neplatný formát e-mailu.';
    if (!password) next.password = 'Zadajte heslo.';
    else if (password.length < 8) next.password = 'Heslo musí mať aspoň 8 znakov.';
    setErrors(next);
    return Object.keys(next).length === 0;
  }

  async function handleSubmit(e) {
    e.preventDefault();
    setGlobalErr('');
    if (locked) return;
    if (trap) return;                // honeypot — silently drop bots
    if (!validate()) return;

    setSubmitting(true);
    let res;
    try {
      res = await API.login(email.trim(), password, remember);
    } catch {
      setSubmitting(false);
      setGlobalErr('Nepodarilo sa spojiť so serverom. Skontrolujte pripojenie.');
      return;
    }

    if (res.status === 429) {
      const until = Date.now() + LOCK_MS;
      setLock((lock.count || 0) + 1, until);
      setLockState({ count: (lock.count || 0) + 1, until });
      setGlobalErr(res.body.message || 'Príliš veľa pokusov. Skúste neskôr.');
      setSubmitting(false); setPassword('');
      return;
    }

    if (res.status !== 200 || !res.body.ok) {
      const count = (lock.count || 0) + 1;
      const left = MAX_ATTEMPTS - count;
      if (count >= MAX_ATTEMPTS) {
        const until = Date.now() + LOCK_MS;
        setLock(count, until);
        setLockState({ count, until });
        setGlobalErr('Príliš veľa neúspešných pokusov. Prihlasovanie je dočasne zablokované.');
      } else {
        setLock(count, 0);
        setLockState({ count, until: 0 });
        setGlobalErr(`Nesprávny e-mail alebo heslo.${left > 0 ? ` Zostáva ${left} ${left === 1 ? 'pokus' : 'pokusy'}.` : ''}`);
      }
      setSubmitting(false); setPassword('');
      return;
    }

    clearLock();
    setLockState({ count: 0, until: 0 });
    setSubmitting(false);

    if (res.body.require2fa) {
      onNeed2FA && onNeed2FA({ email: email.trim(), remember });
    } else {
      onLoggedIn && onLoggedIn(res.body.user);
    }
  }

  function handleForgot(e) {
    e.preventDefault();
    alert('Odkaz na obnovu hesla bude odoslaný na zadaný e-mail. (Ukážka — pripojte sa na backend SuperFaktúra/SMTP.)');
  }

  return (
    <div className="auth-wrap" onKeyDown={handleKey} onKeyUp={handleKey}>
      <div className="auth-left">
        <div className="auth-logo">
          <Logo size={40}/>
          <div className="auth-logo-text">D&amp;D Energy<small>Interný systém</small></div>
        </div>
        <div className="auth-tagline">
          <h2>Energia je <span>biznis.</span><br/>Riaďte ho s prehľadom.</h2>
          <p>Centrálny CRM systém pre objednávky z eshopu, správu produktov, B2B schvaľovanie a interných asistentov — na jednom mieste.</p>
        </div>
        <div className="auth-foot">
          <span>© 2026 D&amp;D Energy s.r.o.</span>
          <span>v2.4.1</span>
          <span>Podpora: it@ddenergy.sk</span>
        </div>
      </div>

      <form className="auth-right" onSubmit={handleSubmit} noValidate autoComplete="on">
        <h3>Prihlásenie do CRM</h3>
        <div className="sub">Zadajte svoje firemné prihlasovacie údaje</div>

        {globalErr && (
          <div className="auth-alert" role="alert">
            <AuthIco.alert/> <span>{globalErr}</span>
          </div>
        )}
        {locked && (
          <div className="auth-alert" role="alert">
            <AuthIco.alert/> <span>Odblokovanie o <b>{secondsLeft}s</b>.</span>
          </div>
        )}

        <div className="auth-form">
          {/* honeypot — hidden from humans */}
          <div className="hp-trap" aria-hidden="true">
            <label>Company</label>
            <input tabIndex={-1} autoComplete="off" value={trap} onChange={e => setTrap(e.target.value)}/>
          </div>

          <div className="field">
            <label htmlFor="login-email">E-mail</label>
            <div className="input-wrap">
              <Ico.mail className="input-ico"/>
              <input
                id="login-email"
                ref={emailRef}
                className={`input ${errors.email ? 'is-invalid' : ''}`}
                type="email"
                name="email"
                autoComplete="username"
                inputMode="email"
                spellCheck="false"
                autoCapitalize="off"
                placeholder="vy@ddenergy.sk"
                value={email}
                onChange={e => { setEmail(e.target.value); if (errors.email) setErrors({ ...errors, email: null }); }}
                aria-invalid={!!errors.email}
                aria-describedby={errors.email ? 'err-email' : undefined}
                disabled={submitting || locked}
              />
            </div>
            {errors.email && <div id="err-email" className="field-err">{errors.email}</div>}
          </div>

          <div className="field">
            <div className="row-between">
              <label htmlFor="login-password">Heslo</label>
              <a href="#" onClick={handleForgot} className="link-muted">Zabudnuté heslo?</a>
            </div>
            <div className="input-wrap">
              <Ico.lock className="input-ico"/>
              <input
                id="login-password"
                className={`input ${errors.password ? 'is-invalid' : ''}`}
                type={showPass ? 'text' : 'password'}
                name="password"
                autoComplete="current-password"
                placeholder="••••••••"
                value={password}
                onChange={e => { setPassword(e.target.value); if (errors.password) setErrors({ ...errors, password: null }); }}
                aria-invalid={!!errors.password}
                aria-describedby={errors.password ? 'err-password' : undefined}
                disabled={submitting || locked}
              />
              <button
                type="button"
                className="input-action"
                onClick={() => setShowPass(s => !s)}
                aria-label={showPass ? 'Skryť heslo' : 'Zobraziť heslo'}
                tabIndex={0}
              >
                {showPass ? <AuthIco.eyeOff/> : <AuthIco.eye/>}
              </button>
            </div>
            {errors.password && <div id="err-password" className="field-err">{errors.password}</div>}
            {caps && <div className="field-warn"><AuthIco.alert/> Caps Lock je zapnutý.</div>}
          </div>

          <label className="checkbox">
            <input type="checkbox" checked={remember} onChange={e => setRemember(e.target.checked)}/>
            <span>Zapamätať toto zariadenie na 30 dní</span>
          </label>

          <button
            type="submit"
            className="btn btn-primary btn-lg btn-block"
            disabled={submitting || locked}
          >
            {submitting ? <><AuthIco.loader/> Prihlasujem…</> : 'Prihlásiť sa'}
          </button>

          <div className="small muted" style={{textAlign:'center', marginTop:6}}>
            Prístup do CRM prideľuje administrátor. Ak nemáte účet, kontaktujte <b>it@ddenergy.sk</b>.
          </div>
        </div>
      </form>
    </div>
  );
}

// ───── 2FA ─────
function TwoFactorScreen({ onVerified, onBack, pendingUser } = {}) {
  const [digits, setDigits] = React.useState(['','','','','','']);
  const [err, setErr] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [useBackup, setUseBackup] = React.useState(false);
  const [backup, setBackup] = React.useState('');
  const [resendIn, setResendIn] = React.useState(0);
  const refs = React.useRef([]);

  React.useEffect(() => { refs.current[0] && refs.current[0].focus(); }, []);
  React.useEffect(() => {
    if (resendIn <= 0) return;
    const id = setInterval(() => setResendIn(s => Math.max(0, s - 1)), 1000);
    return () => clearInterval(id);
  }, [resendIn]);

  function setDigit(i, v) {
    const d = v.replace(/\D/g, '').slice(0, 1);
    const next = [...digits]; next[i] = d; setDigits(next);
    if (d && i < 5) refs.current[i + 1] && refs.current[i + 1].focus();
    if (next.every(x => x.length === 1)) submit(next.join(''));
  }

  function handleKey(i, e) {
    if (e.key === 'Backspace' && !digits[i] && i > 0) refs.current[i - 1].focus();
    if (e.key === 'ArrowLeft' && i > 0) refs.current[i - 1].focus();
    if (e.key === 'ArrowRight' && i < 5) refs.current[i + 1].focus();
  }

  function handlePaste(e) {
    const txt = (e.clipboardData.getData('text') || '').replace(/\D/g, '').slice(0, 6);
    if (!txt) return;
    e.preventDefault();
    const next = ['','','','','',''];
    for (let k = 0; k < txt.length; k++) next[k] = txt[k];
    setDigits(next);
    const last = Math.min(txt.length, 6) - 1;
    refs.current[last] && refs.current[last].focus();
    if (txt.length === 6) submit(txt);
  }

  async function submit(code) {
    setSubmitting(true); setErr('');
    let res;
    try { res = await API.twofa(code); }
    catch { setErr('Nepodarilo sa spojiť so serverom.'); setSubmitting(false); return; }

    if (res.status === 200 && res.body.ok) {
      onVerified && onVerified(res.body.user);
    } else if (res.status === 401 && res.body.error === 'challenge_expired') {
      setErr('Overovacie okno vypršalo. Prihláste sa znova.');
      setTimeout(() => onBack && onBack(), 1200);
    } else {
      setErr(res.body.error === 'invalid_code' ? 'Neplatný kód. Skúste znova.' : 'Overenie zlyhalo.');
      setDigits(['','','','','','']);
      refs.current[0] && refs.current[0].focus();
    }
    setSubmitting(false);
  }

  async function submitBackup(e) {
    e.preventDefault();
    setSubmitting(true); setErr('');
    // Backup codes — same endpoint accepts them once wired on server side.
    let res;
    try { res = await API.twofa(backup.trim().toUpperCase()); }
    catch { setErr('Nepodarilo sa spojiť so serverom.'); setSubmitting(false); return; }

    if (res.status === 200 && res.body.ok) onVerified && onVerified(res.body.user);
    else setErr('Záložný kód neplatí alebo bol už použitý.');
    setSubmitting(false);
  }

  function resend() {
    if (resendIn > 0) return;
    setResendIn(45);
  }

  return (
    <div className="auth-wrap">
      <div className="auth-left">
        <div className="auth-logo">
          <Logo size={40}/>
          <div className="auth-logo-text">D&amp;D Energy<small>Interný systém</small></div>
        </div>
        <div className="auth-tagline">
          <h2>Ešte jeden <span>krok.</span></h2>
          <p>Na ochranu firemných dát používame dvojfaktorové overenie. Otvorte aplikáciu a zadajte 6-ciferný kód.</p>
        </div>
        <div className="auth-foot">
          <span>© 2026 D&amp;D Energy s.r.o.</span>
          <span>v2.4.1</span>
        </div>
      </div>

      <div className="auth-right">
        <div className="auth-badge"><Ico.shield/></div>
        <h3>Dvojfaktorové overenie</h3>
        <div className="sub">
          {useBackup
            ? 'Zadajte jeden z vašich záložných kódov.'
            : <>Zadajte 6-ciferný kód z aplikácie <b>Authy / Google Authenticator</b>.</>}
          {pendingUser && <div className="small muted" style={{marginTop:4}}>Prihlásený ako <b>{pendingUser.email}</b></div>}
        </div>

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

        {!useBackup ? (
          <div className="auth-form">
            <div className="otp-row" onPaste={handlePaste}>
              {digits.map((d, i) => (
                <input
                  key={i}
                  ref={el => refs.current[i] = el}
                  className={`otp-box ${d ? 'filled' : ''}`}
                  type="text"
                  inputMode="numeric"
                  autoComplete={i === 0 ? 'one-time-code' : 'off'}
                  maxLength={1}
                  value={d}
                  onChange={e => setDigit(i, e.target.value)}
                  onKeyDown={e => handleKey(i, e)}
                  aria-label={`Cifra ${i + 1}`}
                  disabled={submitting}
                />
              ))}
            </div>
            <div className="small muted" style={{textAlign:'center'}}>
              Kód sa automaticky odošle po zadaní všetkých 6 cifier.
            </div>
            <button
              type="button"
              className="btn btn-primary btn-lg btn-block"
              disabled={submitting || digits.some(d => !d)}
              onClick={() => submit(digits.join(''))}
            >
              {submitting ? <><AuthIco.loader/> Overujem…</> : 'Overiť a prihlásiť sa'}
            </button>
            <div className="auth-links">
              <a onClick={() => setUseBackup(true)}>Použiť záložný kód</a>
              <span className="sep">·</span>
              <a onClick={resend} className={resendIn > 0 ? 'disabled' : ''}>
                {resendIn > 0 ? `Znova poslať (${resendIn}s)` : 'Znova poslať kód'}
              </a>
              <span className="sep">·</span>
              <a onClick={onBack} className="muted">Späť na prihlásenie</a>
            </div>
          </div>
        ) : (
          <form className="auth-form" onSubmit={submitBackup}>
            <div className="field">
              <label htmlFor="backup-code">Záložný kód</label>
              <input
                id="backup-code"
                className="input"
                placeholder="Napr. A1B2C3D4"
                value={backup}
                onChange={e => setBackup(e.target.value.toUpperCase())}
                maxLength={8}
                autoFocus
                spellCheck="false"
                autoCapitalize="characters"
                autoComplete="one-time-code"
              />
            </div>
            <button type="submit" className="btn btn-primary btn-lg btn-block" disabled={submitting}>
              {submitting ? <><AuthIco.loader/> Overujem…</> : 'Overiť záložný kód'}
            </button>
            <div className="auth-links">
              <a onClick={() => { setUseBackup(false); setErr(''); }}>Späť na kód z aplikácie</a>
              <span className="sep">·</span>
              <a onClick={onBack} className="muted">Späť na prihlásenie</a>
            </div>
          </form>
        )}
      </div>
    </div>
  );
}

// Remember-device check — in production this would be a signed cookie set server-side.
function hasRememberedDevice(email) {
  try {
    const raw = localStorage.getItem('dd_remember_' + btoa(email).slice(0, 16));
    if (!raw) return false;
    const { until } = JSON.parse(raw);
    return until && until > Date.now();
  } catch { return false; }
}
function setRememberedDevice(email, days = 30) {
  try {
    const until = Date.now() + days * 24 * 3600 * 1000;
    localStorage.setItem('dd_remember_' + btoa(email).slice(0, 16), JSON.stringify({ until }));
  } catch {}
}

Object.assign(window, { LoginScreen, TwoFactorScreen, API, hasRememberedDevice, setRememberedDevice });
