/* combo.codes — Gate app */
const DS = window.ComboCodesDesignSystem_019e18;
const { Button, Terminal, Input, StatusDot } = DS;

/* Access control is server-side. The typed key is sent to /auth/login;
   the server resolves the access profile, sets a signed httpOnly cookie,
   and returns where to go. No keys, hashes or rules live in this file. */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "enterAccent": "magenta",
  "ambientLevel": 85,
  "glitchIdle": true,
  "scanlines": true
}/*EDITMODE-END*/;

/* ---- rotating access log ------------------------------------------ */
const LOG_POOL = [
  { text: 'node online · gate.combo.codes', tone: 'ok' },
  { text: 'listening on :443', tone: 'dim' },
  { text: 'tls 1.3 · handshake ok', tone: 'dim' },
  { text: 'visitor detected', tone: 'default' },
  { text: 'fingerprint logged', tone: 'dim' },
  { text: 'auth required · waiting for key', tone: 'warn' },
  { text: '0 errors', tone: 'ok' },
];

function useRotatingLog(size = 5, every = 2400) {
  const [head, setHead] = React.useState(size);
  React.useEffect(() => {
    const id = setInterval(() => setHead((h) => h + 1), every);
    return () => clearInterval(id);
  }, [every]);
  const lines = [];
  for (let i = size; i > 0; i--) {
    lines.push(LOG_POOL[(head - i + LOG_POOL.length * 100) % LOG_POOL.length]);
  }
  return lines;
}

/* ---- the logo assembly --------------------------------------------- */
function GateLogo() {
  return (
    <div className="cclogo" role="img" aria-label="combo.codes">
      <span className="st lb"><span className="bk" style={{ color: 'var(--acid-lime)' }}>{'{'}</span><span className="fr" style={{ color: 'var(--pulse-purple)' }}>{'{'}</span></span>
      <span className="typewrap"><span className="type"><span className="st"><span className="bk" style={{ color: 'var(--pulse-purple)' }}>combo.codes</span><span className="fr">combo<span className="dot">.</span>codes</span></span></span><span className="caret" aria-hidden="true"><span className="b"></span><span className="f"></span></span></span>
      <span className="st rb"><span className="bk" style={{ color: 'var(--pulse-purple)' }}>{'}'}</span><span className="fr" style={{ color: 'var(--acid-lime)' }}>{'}'}</span></span>
      <span className="st sc"><span className="bk" style={{ color: 'var(--acid-lime)' }}>;</span><span className="fr" style={{ color: 'var(--pulse-purple)' }}>;</span></span>
    </div>
  );
}

/* ---- ambient furniture ---------------------------------------------- */
function Ambient({ level }) {
  const logLines = useRotatingLog();
  return (
    <div className="gate__ambient" style={{ '--gate-ambient': level / 100 }} aria-hidden="true">
      <span className="amb amb-corner amb-corner--tl"></span>
      <span className="amb amb-corner amb-corner--tr"></span>
      <span className="amb amb-corner amb-corner--bl"></span>
      <span className="amb amb-corner amb-corner--br"></span>

      <div className="amb amb-term amb--float" style={{ top: 'var(--space-16)', left: 'var(--space-12)', animationDuration: '13s' }}>
        <Terminal title="gate/access.log" lines={logLines} caret></Terminal>
      </div>

      <div className="amb amb-term amb--float" style={{ bottom: 'var(--space-16)', right: 'var(--space-12)', animationDuration: '11s', animationDelay: '-4s' }}>
        <Terminal title="handshake.sh" lines={[
          { text: 'cipher agreed · session sealed', tone: 'dim' },
          { text: 'gate locked', tone: 'default' },
          { text: 'awaiting key_', tone: 'warn' },
        ]}></Terminal>
      </div>

      <pre className="amb amb-code cc-code amb--float" style={{ top: 'var(--space-20)', right: 'var(--space-16)', animationDuration: '15s', animationDelay: '-7s' }}>
<span className="tok-key">const</span> visitor = <span className="tok-key">await</span> gate.<span className="tok-fn">identify</span>();{'\n'}
<span className="tok-key">if</span> (visitor.key) {'{'}{'\n'}
{'  '}vault.<span className="tok-fn">open</span>(visitor.key.zone);{'\n'}
{'}'}{'\n'}
<span className="tok-com">// if you weren't invited,</span>{'\n'}
<span className="tok-com">// this is just a logo.</span>
      </pre>

      <div className="amb amb-caption" style={{ bottom: 'var(--space-16)', left: 'var(--space-12)' }}>
        <div>&gt; combo.codes/gate v2.6</div>
        <div>&gt; auth: key required</div>
        <div>&gt; zones: private</div>
      </div>

      <span className="amb amb-glyph" style={{ top: '12%', left: '26%', fontSize: '240px' }}>{'{'}</span>
      <span className="amb amb-glyph" style={{ bottom: '8%', right: '27%', fontSize: '240px' }}>;</span>
    </div>
  );
}

/* ---- access modal ----------------------------------------------------- */
function AccessModal({ onClose }) {
  const [value, setValue] = React.useState('');
  const [phase, setPhase] = React.useState('idle'); // idle | denied | granted
  const [attempts, setAttempts] = React.useState(0);
  const [shake, setShake] = React.useState(false);
  const [grantedZone, setGrantedZone] = React.useState(null);
  const [grantStep, setGrantStep] = React.useState(0);

  const deny = () => {
    setAttempts((a) => a + 1);
    setPhase('denied');
    setShake(true);
    setTimeout(() => setShake(false), 280);
  };

  const submit = async () => {
    if (phase === 'granted' || phase === 'checking') return;
    const key = value.trim();
    if (!key) return;
    setPhase('checking');
    try {
      const res = await fetch('/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'same-origin',
        body: JSON.stringify({ key }),
      });
      const data = await res.json().catch(() => null);
      if (res.ok && data && data.ok) {
        setPhase('granted');
        setGrantedZone({ label: data.label || 'ACCESS_GRANTED', kind: data.kind || 'document' });
        [1, 2, 3].forEach((n) => setTimeout(() => setGrantStep(n), 240 + n * 360));
        setTimeout(() => { window.location.href = data.redirect || '/'; }, 1900);
        return;
      }
    } catch (e) { /* network / parse error — fall through to denied */ }
    deny();
  };

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape' && phase !== 'granted') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [phase, onClose]);

  const cls = [
    'gatemodal',
    phase === 'denied' ? 'gatemodal--denied' : '',
    phase === 'granted' ? 'gatemodal--granted' : '',
    shake ? 'gatemodal--shake' : '',
  ].filter(Boolean).join(' ');

  return (
    <div className="gatemodal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget && phase !== 'granted') onClose(); }}>
      <div className={cls} role="dialog" aria-modal="true" aria-label="Access console">
        <div className="cc-term__bar">
          <span className="cc-term__dot" style={{ background: 'var(--hot-magenta)' }}></span>
          <span className="cc-term__dot" style={{ background: 'var(--cyber-yellow)' }}></span>
          <span className="cc-term__dot" style={{ background: 'var(--acid-lime)' }}></span>
          <span className="cc-term__title">auth.console — combo.codes</span>
        </div>

        {phase !== 'granted' ? (
          <div className="gatemodal__body">
            <div className="gatemodal__lead">identify yourself<span className="cc-caret">_</span></div>
            <Input
              label="Access key"
              type="text"
              placeholder="your-access-key"
              autoFocus
              autoComplete="off"
              spellCheck="false"
              value={value}
              error={phase === 'denied'}
              hint="keys are issued personally · one key opens one room"
              onChange={(e) => { setValue(e.target.value); if (phase === 'denied') setPhase('idle'); }}
              onKeyDown={(e) => { if (e.key === 'Enter') submit(); }}
            ></Input>
            <div className={'gatemodal__status' + (phase === 'denied' ? ' gatemodal__status--denied' : '')}>
              {phase === 'denied'
                ? `> access denied · key not recognized [attempt ${String(attempts).padStart(2, '0')}]`
                : '> session is encrypted · nothing is stored'}
            </div>
            <div className="gatemodal__actions">
              <Button variant="ghost" onClick={onClose}>Cancel</Button>
              <Button variant="primary" onClick={submit}>Unlock</Button>
            </div>
          </div>
        ) : (
          <div className="gatemodal__body">
            <div className="gatemodal__granted">
              {grantStep >= 1 ? <div className="gl gl--ok">key accepted</div> : null}
              {grantStep >= 2 ? <div className="gl">zone: {grantedZone.label}</div> : null}
              {grantStep >= 3 ? <div className="gl">opening {grantedZone.kind}<span className="cc-caret">_</span></div> : null}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

/* ---- the gate ---------------------------------------------------------- */
function Gate() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [modalOpen, setModalOpen] = React.useState(false);

  return (
    <div
      className={'gate' + (t.scanlines ? '' : ' gate--noscan') + ' cc-dotgrid'}
      data-accent={t.enterAccent}
      data-glitch={t.glitchIdle ? 'on' : 'off'}
      data-screen-label="Gate"
    >
      <Ambient level={t.ambientLevel}></Ambient>
      {t.scanlines ? <div className="gate__scan"></div> : null}

      <div className="gate__center">
        <span className="cc-eyebrow">{'{'} PRIVATE_ACCESS_NODE {'}'}</span>
        <GateLogo></GateLogo>
        <div className="gate__status">
          <StatusDot status="success" pulse></StatusDot>
          <span>node online · access by key only</span>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 'var(--space-3)' }}>
          <Button variant="cta" size="lg" className="gate-enter" onClick={() => setModalOpen(true)}>Enter</Button>
          <span className="gate-enter-hint">your key was issued with your invitation</span>
        </div>
      </div>

      <div className="gate__footerline cc-prompt">combo.codes<span className="cc-caret">_</span></div>

      {modalOpen ? <AccessModal onClose={() => setModalOpen(false)}></AccessModal> : null}

      <TweaksPanel>
        <TweakSection label="Enter button"></TweakSection>
        <TweakRadio label="Accent" value={t.enterAccent} options={['magenta', 'purple']} onChange={(v) => setTweak('enterAccent', v)}></TweakRadio>
        <TweakSection label="Atmosphere"></TweakSection>
        <TweakSlider label="Ambient level" value={t.ambientLevel} min={0} max={100} unit="%" onChange={(v) => setTweak('ambientLevel', v)}></TweakSlider>
        <TweakToggle label="Glitch idle" value={t.glitchIdle} onChange={(v) => setTweak('glitchIdle', v)}></TweakToggle>
        <TweakToggle label="Scanlines" value={t.scanlines} onChange={(v) => setTweak('scanlines', v)}></TweakToggle>
      </TweaksPanel>
    </div>
  );
}

window.GateApp = Gate;
if (!window.__standalone) {
  ReactDOM.createRoot(document.getElementById('root')).render(<Gate></Gate>);
}
