/* ============================================================
   TRUSTED NBT EDITOR — Site 2 — terminal.js
   Same backend API as site 1. Completely separate JS.
   API base: /api  (same-origin or set SITE2_API_BASE)
   ============================================================ */

'use strict';

/* ── CONFIG ─────────────────────────────────────────────────── */
const API = (typeof SITE2_API_BASE !== 'undefined') ? SITE2_API_BASE : '/api';

/* ── STATE ──────────────────────────────────────────────────── */
const S = {
  user: null,
  mode: 'login',
  postTarget: null,
  otpInterval: null,
  otpSecs: 600,
};

/* ── API ────────────────────────────────────────────────────── */
async function api(method, path, body) {
  const opts = { method, credentials: 'include', headers: { 'Content-Type': 'application/json' } };
  if (body) opts.body = JSON.stringify(body);
  const res = await fetch(API + path, opts);
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
  return data;
}
const GET  = p    => api('GET',  p);
const POST = (p,b)=> api('POST', p, b);

/* ── BOOT SEQUENCE ──────────────────────────────────────────── */
(function boot() {
  const bootEl  = document.getElementById('boot');
  const lines   = document.getElementById('boot-lines');
  const bar     = document.getElementById('boot-bar');
  const shell   = document.getElementById('shell');

  const sequence = [
    { ms: 80,  cls: 'ok',   text: '[  OK  ] kernel: loading nbt-editor runtime' },
    { ms: 160, cls: '',     text: '         checking cpu features...' },
    { ms: 240, cls: 'ok',   text: '[  OK  ] nbt-schema: registry loaded (11 schemas)' },
    { ms: 320, cls: 'ok',   text: '[  OK  ] crypto: sha-256 engine ready' },
    { ms: 440, cls: 'ok',   text: '[  OK  ] session: cookie store initialized' },
    { ms: 560, cls: 'ok',   text: '[  OK  ] net: connecting to api backend' },
    { ms: 700, cls: 'ok',   text: '[  OK  ] tls: certificate verified' },
    { ms: 820, cls: 'warn', text: '[ WARN ] auth: no active session — guest mode' },
    { ms: 960, cls: 'ok',   text: '[  OK  ] renderer: terminal ui ready' },
  ];

  let pct = 0;
  const barTimer = setInterval(() => {
    pct = Math.min(pct + Math.random() * 4 + 0.5, 100);
    bar.style.width = pct + '%';
    if (pct >= 100) clearInterval(barTimer);
  }, 40);

  sequence.forEach(({ ms, cls, text }) => {
    setTimeout(() => {
      const d = document.createElement('div');
      d.className = 'boot-line' + (cls ? ' ' + cls : '');
      d.textContent = text;
      lines.appendChild(d);
    }, ms);
  });

  setTimeout(() => {
    bootEl.classList.add('fade');
    shell.classList.remove('hidden');
    requestAnimationFrame(() => requestAnimationFrame(() => shell.classList.add('visible')));
    setTimeout(() => bootEl.remove(), 700);
    animateStats();
    startTermDemo();
    setFooterClock();
  }, 1200);
})();

/* ── NAV ────────────────────────────────────────────────────── */
function showPage(name) {
  document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
  document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
  document.getElementById('page-' + name)?.classList.add('active');
  document.querySelector(`[data-page="${name}"]`)?.classList.add('active');
  document.getElementById('path-section').textContent = name;
  window.scrollTo({ top: 0, behavior: 'smooth' });

  if (name === 'releases') loadReleases();
  if (name === 'changelog') loadChangelog();
}

document.querySelectorAll('.nav-btn').forEach(b =>
  b.addEventListener('click', () => showPage(b.dataset.page))
);

document.getElementById('home-dl-btn').addEventListener('click', () => showPage('releases'));
document.getElementById('home-cl-btn').addEventListener('click', () => showPage('changelog'));

/* ── STAT COUNTERS ──────────────────────────────────────────── */
function animateStats() {
  document.querySelectorAll('.stat-val').forEach(el => {
    const target = +el.dataset.target;
    let cur = 0;
    const step = target / 60;
    const t = setInterval(() => {
      cur = Math.min(cur + step, target);
      el.textContent = Math.floor(cur).toLocaleString();
      if (cur >= target) clearInterval(t);
    }, 22);
  });
}

/* ── TERMINAL DEMO ──────────────────────────────────────────── */
function startTermDemo() {
  const body = document.getElementById('term-demo');
  const lines = [
    { delay: 200,  html: '<span class="t-cmd">$ nbt --inspect --held-item</span>' },
    { delay: 600,  html: '<span class="t-dim">reading item from slot 0...</span>' },
    { delay: 1000, html: '<span class="t-ok">✓ item found: minecraft:diamond_sword</span>' },
    { delay: 1400, html: '' },
    { delay: 1600, html: '<span class="t-dim">Tags:</span>' },
    { delay: 1800, html: '  <span class="t-val">Damage</span>: <span class="t-ok">0</span>' },
    { delay: 2000, html: '  <span class="t-val">Enchantments</span>: [' },
    { delay: 2200, html: '    <span class="t-dim">{ id: sharpness, lvl: 5 }</span>' },
    { delay: 2400, html: '    <span class="t-dim">{ id: unbreaking, lvl: 3 }</span>' },
    { delay: 2600, html: '  ]' },
    { delay: 2800, html: '  <span class="t-val">display.Name</span>: <span class="t-ok">"Calibrated Edge"</span>' },
    { delay: 3000, html: '' },
    { delay: 3200, html: '<span class="t-cmd">$ nbt --export-give</span>' },
    { delay: 3600, html: '<span class="t-ok">✓ /give command copied to clipboard</span>' },
    { delay: 4000, html: '' },
    { delay: 4200, html: '<span class="t-caret">▌</span>' },
  ];

  lines.forEach(({ delay, html }) => {
    setTimeout(() => {
      // Remove caret if present
      body.querySelector('.t-caret')?.parentElement?.remove();
      const row = document.createElement('div');
      row.innerHTML = html;
      body.appendChild(row);
    }, delay);
  });
}

/* ── FOOTER CLOCK ───────────────────────────────────────────── */
function setFooterClock() {
  const el = document.getElementById('foot-ts');
  const update = () => {
    el.textContent = new Date().toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
  };
  update();
  setInterval(update, 1000);
}

/* ── RELEASES ───────────────────────────────────────────────── */
let relLoaded = false;

async function loadReleases() {
  if (relLoaded) return;
  const loading = document.getElementById('rel-loading');
  const errEl   = document.getElementById('rel-error');
  const table   = document.getElementById('rel-table');
  const note    = document.getElementById('rel-login-note');
  const tbody   = document.getElementById('rtable-body');

  loading.classList.remove('hidden');
  errEl.classList.add('hidden');
  table.classList.add('hidden');

  if (!S.user) note.classList.remove('hidden');

  try {
    const versions = await GET('/mods/versions');
    loading.classList.add('hidden');

    if (!versions.length) {
      errEl.textContent = 'No releases available yet.';
      errEl.classList.remove('hidden');
      return;
    }

    tbody.innerHTML = versions.map(v => `
      <div class="rtable-row${v.is_latest ? ' is-latest' : ''}">
        <span>${v.is_latest ? '<span class="vtag">latest</span>' : ''}v${v.version}</span>
        <span>${v.filename}</span>
        <span>${fmtBytes(v.file_size)}</span>
        <span class="r-hash" title="${v.sha256}">${v.sha256.slice(0,8)}…${v.sha256.slice(-4)}</span>
        <span><span class="scan-tag ${v.scan_status}">${v.scan_status}</span></span>
        <button class="shell-btn${v.is_latest ? ' primary' : ''} small"
                onclick="handleDownload(${v.id},'${v.version}')">
          ${S.user ? '↓ download' : '🔒 login'}
        </button>
      </div>`).join('');

    table.classList.remove('hidden');
    relLoaded = true;
  } catch (e) {
    loading.classList.add('hidden');
    errEl.textContent = '[ ERR ] ' + e.message;
    errEl.classList.remove('hidden');
  }
}

function handleDownload(id, version) {
  if (!S.user) { S.postTarget = 'releases'; openAuth(); return; }
  const a = document.createElement('a');
  a.href = `${API}/mods/download/${id}`;
  a.download = `nbt-editor-${version}.jar`;
  a.click();
}

document.getElementById('rel-login-link')?.addEventListener('click', e => {
  e.preventDefault(); S.postTarget = 'releases'; openAuth();
});

function fmtBytes(b) {
  if (!b) return '—';
  return b > 1048576 ? (b/1048576).toFixed(1)+' MB' : (b/1024).toFixed(0)+' KB';
}

/* ── CHANGELOG ──────────────────────────────────────────────── */
let clLoaded = false;

async function loadChangelog() {
  if (clLoaded) return;
  const loading = document.getElementById('cl-loading');
  const errEl   = document.getElementById('cl-error');
  const list    = document.getElementById('cl-entries');

  loading.classList.remove('hidden');
  errEl.classList.add('hidden');

  try {
    const entries = await GET('/changelog');
    loading.classList.add('hidden');

    if (!entries.length) {
      list.innerHTML = '<p style="color:var(--text-dim);padding:40px 0">no changelog entries yet.</p>';
      list.classList.remove('hidden');
      return;
    }

    list.innerHTML = entries.map(e => `
      <div class="cl-entry">
        <div class="cl-ver-line">
          <span class="vtag${e.is_latest ? '' : ' old'}">v${e.version}</span>
          ${e.is_latest ? '<span style="font-size:0.7rem;color:var(--amber)">← current</span>' : ''}
        </div>
        <div class="cl-meta">${fmtDate(e.created_at)} · by ${escHtml(e.uploaded_by)}</div>
        <div class="cl-notes">${escHtml(e.notes || 'No notes provided.')}</div>
      </div>`).join('');

    list.classList.remove('hidden');
    clLoaded = true;
  } catch (e) {
    loading.classList.add('hidden');
    errEl.textContent = '[ ERR ] ' + e.message;
    errEl.classList.remove('hidden');
  }
}

function fmtDate(ts) {
  if (!ts) return '—';
  return new Date(ts * 1000).toISOString().slice(0, 10);
}

function escHtml(s) {
  return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

/* ── AUTH MODAL ─────────────────────────────────────────────── */
const modal = document.getElementById('auth-modal');

function openAuth(mode) {
  S.mode = mode || 'login';
  setMode(S.mode);
  goAStep('1');
  modal.classList.remove('hidden');
}

function closeAuth() {
  modal.classList.add('hidden');
  stopOtpTimer();
  clearAuthErrors();
}

function setMode(m) {
  const isReg = m === 'register';
  document.getElementById('a-mode-label').textContent = isReg ? 'session --register' : 'session --login';
  document.getElementById('auth-terminal-title').textContent = `auth@nbt-editor — ${m}`;
  document.getElementById('a-username-field').style.display = isReg ? '' : 'none';
  document.getElementById('a-switch-btn').textContent = isReg ? 'login instead' : 'register instead';
}

function goAStep(id) {
  document.querySelectorAll('.a-step').forEach(s => s.classList.remove('active'));
  const map = { '1':'a-step-1', 'reg-qr':'a-step-reg-qr', 'reg-email':'a-step-reg-email', '2':'a-step-2', '3':'a-step-3', 'ok':'a-step-ok' };
  document.getElementById(map[id])?.classList.add('active');
}

function clearAuthErrors() {
  ['a1-err','a2-err','a3-err','are-err'].forEach(id => {
    const el = document.getElementById(id);
    if (el) { el.textContent = ''; el.classList.add('hidden'); }
  });
}

function showAErr(id, msg) {
  const el = document.getElementById(id);
  if (!el) return;
  el.textContent = '[ ERR ] ' + msg;
  el.classList.remove('hidden');
}

// Open / close triggers
document.getElementById('auth-btn').addEventListener('click', () => {
  if (S.user) { doLogout(); return; }
  openAuth('login');
});
document.getElementById('auth-backdrop').addEventListener('click', closeAuth);
document.getElementById('auth-close-dot').addEventListener('click', closeAuth);

// Switch mode
document.getElementById('a-switch-btn').addEventListener('click', () => {
  S.mode = S.mode === 'login' ? 'register' : 'login';
  setMode(S.mode);
  goAStep('1');
  clearAuthErrors();
});

/* ── AUTH STEP 1 ────────────────────────────────────────────── */
document.getElementById('a1-btn').addEventListener('click', async () => {
  clearAuthErrors();
  const email = document.getElementById('a-email').value.trim();
  const pass  = document.getElementById('a-pass').value;
  const btn   = document.getElementById('a1-btn');

  if (!email || !pass) { showAErr('a1-err', 'email and password required.'); return; }

  if (S.mode === 'register') {
    const username = document.getElementById('a-username').value.trim();
    if (!username) { showAErr('a1-err', 'username required.'); return; }
    if (pass.length < 12) { showAErr('a1-err', 'password must be at least 12 characters.'); return; }

    btn.disabled = true; btn.textContent = 'registering...';
    try {
      const data = await POST('/auth/register', { username, email, password: pass });
      document.getElementById('qr-img').src = data.totpQr;
      goAStep('reg-qr');
    } catch (e) { showAErr('a1-err', e.message); }
    finally { btn.disabled = false; btn.textContent = 'execute →'; }

  } else {
    btn.disabled = true; btn.textContent = 'verifying...';
    try {
      await POST('/auth/login', { email, password: pass });
      buildOtpRow('otp-login-boxes');
      goAStep('2');
      startOtpTimer();
    } catch (e) { showAErr('a1-err', e.message); }
    finally { btn.disabled = false; btn.textContent = 'execute →'; }
  }
});

/* ── REGISTER: QR done ──────────────────────────────────────── */
document.getElementById('a-qr-done-btn').addEventListener('click', () => goAStep('reg-email'));

/* ── REGISTER: Email verify ─────────────────────────────────── */
document.getElementById('a-reg-verify-btn').addEventListener('click', async () => {
  const email = document.getElementById('a-email').value.trim();
  const code  = document.getElementById('a-reg-code').value.trim();
  const btn   = document.getElementById('a-reg-verify-btn');
  if (!code) { showAErr('are-err', 'enter the code from your email.'); return; }

  btn.disabled = true; btn.textContent = 'verifying...';
  try {
    await POST('/auth/verify-email', { email, code });
    goAStep('ok');
    document.querySelector('#a-step-ok .a-ok-text .a-info').textContent =
      'Email verified. Your account is now active. Login to start a session.';
    S.user = null;
  } catch (e) { showAErr('are-err', e.message); }
  finally { btn.disabled = false; btn.textContent = 'verify →'; }
});

/* ── STEP 2: Email OTP ──────────────────────────────────────── */
function buildOtpRow(containerId) {
  const wrap = document.getElementById(containerId);
  wrap.innerHTML = '';
  for (let i = 0; i < 6; i++) {
    const b = document.createElement('input');
    b.type = 'text'; b.maxLength = 1;
    b.className = 'otp-box'; b.inputMode = 'numeric';
    b.addEventListener('input', () => {
      b.value = b.value.replace(/\D/, '');
      if (b.value) b.nextElementSibling?.focus();
    });
    b.addEventListener('keydown', e => {
      if (e.key === 'Backspace' && !b.value) b.previousElementSibling?.focus();
    });
    wrap.appendChild(b);
  }
  wrap.firstChild?.focus();
}

function getOtpVal(containerId) {
  return [...document.querySelectorAll(`#${containerId} .otp-box`)].map(b => b.value).join('');
}

document.getElementById('a2-btn').addEventListener('click', async () => {
  clearAuthErrors();
  const code = getOtpVal('otp-login-boxes');
  if (code.length < 6) { showAErr('a2-err', 'enter all 6 digits.'); return; }

  const btn = document.getElementById('a2-btn');
  btn.disabled = true; btn.textContent = 'verifying...';
  try {
    await POST('/auth/login/verify-email-otp', { code });
    stopOtpTimer();
    buildOtpRow('totp-login-boxes');
    goAStep('3');
  } catch (e) { showAErr('a2-err', e.message); }
  finally { btn.disabled = false; btn.textContent = 'verify →'; }
});

document.getElementById('a-resend-btn').addEventListener('click', async () => {
  stopOtpTimer();
  const email = document.getElementById('a-email').value.trim();
  const pass  = document.getElementById('a-pass').value;
  try {
    await POST('/auth/login', { email, password: pass });
    buildOtpRow('otp-login-boxes');
    startOtpTimer();
  } catch (e) { showAErr('a2-err', 'resend failed: ' + e.message); }
});

function startOtpTimer() {
  S.otpSecs = 600;
  updateOtpTimer();
  S.otpInterval = setInterval(() => {
    S.otpSecs--;
    updateOtpTimer();
    if (S.otpSecs <= 0) stopOtpTimer();
  }, 1000);
}

function stopOtpTimer() { clearInterval(S.otpInterval); S.otpInterval = null; }

function updateOtpTimer() {
  const m = String(Math.floor(S.otpSecs / 60)).padStart(2,'0');
  const s = String(S.otpSecs % 60).padStart(2,'0');
  const el = document.getElementById('a-timer');
  if (el) el.textContent = `${m}:${s}`;
}

/* ── STEP 3: TOTP ───────────────────────────────────────────── */
document.getElementById('a3-btn').addEventListener('click', async () => {
  clearAuthErrors();
  const totpCode = getOtpVal('totp-login-boxes');
  if (totpCode.length < 6) { showAErr('a3-err', 'enter all 6 digits from your authenticator.'); return; }

  const btn = document.getElementById('a3-btn');
  btn.disabled = true; btn.textContent = 'authenticating...';
  try {
    const data = await POST('/auth/login/verify-totp', { totpCode });
    S.user = data.user;
    updateSessionUI();
    goAStep('ok');
  } catch (e) { showAErr('a3-err', e.message); }
  finally { btn.disabled = false; btn.textContent = 'authenticate →'; }
});

/* ── AUTH DONE ──────────────────────────────────────────────── */
document.getElementById('a-ok-btn').addEventListener('click', () => {
  closeAuth();
  if (!S.user) {
    // Registration — switch to login flow
    openAuth('login');
    return;
  }
  const t = S.postTarget; S.postTarget = null;
  if (t) showPage(t);
  // Refresh release buttons to show "↓ download"
  relLoaded = false; clLoaded = false;
  if (document.getElementById('page-releases').classList.contains('active')) loadReleases();
});

/* ── SESSION UI ─────────────────────────────────────────────── */
function updateSessionUI() {
  if (!S.user) return;
  const ind = document.getElementById('session-indicator');
  ind.className = 'session-on';
  ind.innerHTML = `<span class="led"></span><span id="session-label">${S.user.username}</span>`;
  const btn = document.getElementById('auth-btn');
  btn.textContent = 'logout';
  document.getElementById('rel-login-note').classList.add('hidden');
}

async function doLogout() {
  try { await POST('/auth/logout'); } catch (_) {}
  S.user = null;
  const ind = document.getElementById('session-indicator');
  ind.className = 'session-off';
  ind.innerHTML = '<span class="led"></span><span id="session-label">no session</span>';
  document.getElementById('auth-btn').textContent = 'login';
  relLoaded = false; clLoaded = false;
  if (document.getElementById('page-releases').classList.contains('active')) {
    relLoaded = false; loadReleases();
  }
}
