(function () {
  function basePath() {
    return document.body.getAttribute('data-base-path') || '';
  }

  function canOperate() {
    return document.body.getAttribute('data-can-sl-operate') === '1';
  }

  function canAdmin() {
    return document.body.getAttribute('data-can-sl-admin') === '1';
  }

  function apiUrl(action, params) {
    const q = new URLSearchParams(params || {});
    q.set('action', action);
    return basePath() + '/api/short_links.php?' + q.toString();
  }

  function setStatus(msg, isError) {
    const el = document.getElementById('sl-status');
    if (!el) return;
    el.textContent = msg;
    el.classList.toggle('error', !!isError);
  }

  async function fetchJson(url, opts) {
    const res = await fetch(url, Object.assign({ credentials: 'same-origin' }, opts || {}));
    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.ok === false) {
      const err = data.error || data.reason || ('HTTP ' + res.status);
      throw new Error(err);
    }
    return data;
  }

  function esc(s) {
    const d = document.createElement('div');
    d.textContent = s == null ? '' : String(s);
    return d.innerHTML;
  }

  function truncate(s, n) {
    const t = String(s || '');
    return t.length <= n ? t : t.slice(0, n - 1) + '…';
  }

  let selectedBearerId = 0;
  let selectedBearerLabel = '';

  function bearerCaps(b) {
    const parts = [];
    if (b.can_temporary) parts.push('temp');
    if (b.can_permanent) parts.push('perm');
    return parts.length ? parts.join(', ') : '—';
  }

  function renderBearers(bearers) {
    const tbody = document.getElementById('sl-bearers-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    if (!bearers || !bearers.length) {
      tbody.innerHTML = '<tr><td colspan="8" class="muted">No bearer tokens yet — mint one below.</td></tr>';
      return;
    }
    (bearers || []).forEach((b) => {
      const tr = document.createElement('tr');
      const active = b.active !== false && !b.revoked_at;
      const status = active ? '<span class="tag-pill">active</span>' : 'revoked';
      const revokeBtn = canOperate() && active
        ? ' <button type="button" class="btn btn-sm" data-revoke-bearer="' + esc(String(b.id)) + '">Revoke</button>'
        : '';
      const viewBtn =
        '<button type="button" class="btn btn-sm btn-primary" data-view-links="' + esc(String(b.id)) + '" data-label="' + esc(b.label || '') + '">Links</button>';
      tr.innerHTML =
        '<td>' + esc(b.id) + '</td>' +
        '<td>' + esc(b.label) + '</td>' +
        '<td>' + status + '</td>' +
        '<td><code>' + esc(bearerCaps(b)) + '</code></td>' +
        '<td>' + esc(b.link_count) + (b.expired_link_count > 0 ? ' <span class="muted">(' + esc(b.expired_link_count) + ' exp)</span>' : '') + '</td>' +
        '<td>' + esc(b.rate_limit_per_hour) + '</td>' +
        '<td>' + esc(b.created_at || '—') + '</td>' +
        '<td>' + viewBtn + revokeBtn + '</td>';
      tbody.appendChild(tr);
    });
  }

  function renderSigners(signers) {
    const tbody = document.getElementById('sl-signers-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    if (!signers || !signers.length) {
      tbody.innerHTML = '<tr><td colspan="5" class="muted">No signer keys — mint one for permanent links.</td></tr>';
      return;
    }
    (signers || []).forEach((s) => {
      const tr = document.createElement('tr');
      const active = s.active !== false && !s.revoked_at;
      const status = active ? '<span class="tag-pill">active</span>' : 'revoked';
      const revokeBtn = canOperate() && active
        ? ' <button type="button" class="btn btn-sm" data-revoke-signer="' + esc(String(s.id)) + '">Revoke</button>'
        : '';
      tr.innerHTML =
        '<td>' + esc(s.id) + '</td>' +
        '<td>' + esc(s.label) + '</td>' +
        '<td>' + status + '</td>' +
        '<td>' + esc(s.created_at || '—') + '</td>' +
        '<td>' + revokeBtn + '</td>';
      tbody.appendChild(tr);
    });
  }

  function renderLinks(links) {
    const tbody = document.getElementById('sl-links-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    if (!links || !links.length) {
      tbody.innerHTML = '<tr><td colspan="5" class="muted">No links for this bearer.</td></tr>';
      return;
    }
    (links || []).forEach((l) => {
      const tr = document.createElement('tr');
      const exp = l.expired
        ? '<span class="muted">expired</span>'
        : (l.ttl_seconds === 0 || !l.expires_at ? '<span class="tag-pill">permanent</span>' : esc(l.expires_at));
      tr.innerHTML =
        '<td><a href="' + esc(l.short_url) + '" target="_blank" rel="noopener">' + esc(l.short_url) + '</a> ' +
        '<button type="button" class="btn btn-sm" data-copy="' + esc(l.short_url) + '">Copy</button></td>' +
        '<td title="' + esc(l.origin) + '">' + esc(truncate(l.origin, 64)) + '</td>' +
        '<td>' + exp + '</td>' +
        '<td>' + esc(l.access_count) + '</td>' +
        '<td><a class="btn btn-sm" href="' + esc(l.qr_url) + '" target="_blank" rel="noopener">PNG</a></td>';
      tbody.appendChild(tr);
    });
  }

  function renderAudit(rows) {
    const tbody = document.getElementById('sl-audit-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    if (!rows || !rows.length) {
      tbody.innerHTML = '<tr><td colspan="5" class="muted">No audit events.</td></tr>';
      return;
    }
    (rows || []).forEach((e) => {
      const tr = document.createElement('tr');
      tr.innerHTML =
        '<td>' + esc(e.created_at) + '</td>' +
        '<td>' + esc(e.event) + '</td>' +
        '<td>' + esc(e.bearer_id != null ? e.bearer_id : '—') + '</td>' +
        '<td>' + esc(e.slug || '—') + '</td>' +
        '<td>' + esc(e.detail || '—') + '</td>';
      tbody.appendChild(tr);
    });
  }

  function showSecretModal(modalId, valueId, value) {
    const modal = document.getElementById(modalId);
    const val = document.getElementById(valueId);
    if (!modal || !val) return;
    val.textContent = value;
    modal.hidden = false;
  }

  function hideModal(modalId) {
    const modal = document.getElementById(modalId);
    if (modal) modal.hidden = true;
  }

  function syncPermanentUi() {
    const permCb = document.getElementById('sl-permanent-cb');
    const ttlWrap = document.getElementById('sl-ttl-wrap');
    const signerWrap = document.getElementById('sl-signer-wrap');
    const ttlInput = document.getElementById('sl-ttl-input');
    const permanent = permCb && permCb.checked;
    if (ttlWrap) ttlWrap.hidden = !!permanent;
    if (signerWrap) signerWrap.hidden = !permanent;
    if (ttlInput && permanent) ttlInput.value = '0';
  }

  function syncMintPermanentUi() {
    const permCb = document.getElementById('sl-can-permanent');
    const wrap = document.getElementById('sl-mint-signer-wrap');
    if (wrap) wrap.hidden = !(permCb && permCb.checked);
  }

  async function loadLinks(bearerId, label) {
    selectedBearerId = bearerId;
    selectedBearerLabel = label || String(bearerId);
    const section = document.getElementById('sl-links-section');
    const labelEl = document.getElementById('sl-links-bearer-label');
    const hidden = document.getElementById('sl-shorten-bearer-id');
    if (section) section.hidden = false;
    if (labelEl) labelEl.textContent = selectedBearerLabel + ' (#' + bearerId + ')';
    if (hidden) hidden.value = String(bearerId);
    setStatus('Loading links…');
    const data = await fetchJson(apiUrl('links', { bearer_id: String(bearerId) }));
    renderLinks(data.links);
    setStatus('Links for bearer #' + bearerId);
  }

  async function refresh() {
    setStatus('Loading…');
    try {
      const data = await fetchJson(apiUrl('dashboard'));
      renderBearers(data.bearers);
      renderSigners(data.signers);
      renderAudit(data.audit);
      if (selectedBearerId > 0) {
        await loadLinks(selectedBearerId, selectedBearerLabel);
      }
      setStatus('Updated ' + new Date().toLocaleTimeString() + ' · ' + (data.public_base || ''));
    } catch (e) {
      setStatus('Failed: ' + e.message, true);
    }
  }

  document.addEventListener('click', async (ev) => {
    const t = ev.target;
    if (!(t instanceof HTMLElement)) return;

    if (t.id === 'sl-token-close' || t.closest('#sl-token-close')) {
      hideModal('sl-token-modal');
      return;
    }
    if (t.id === 'sl-signer-close' || t.closest('#sl-signer-close')) {
      hideModal('sl-signer-modal');
      return;
    }
    if (t.id === 'sl-token-copy') {
      const val = document.getElementById('sl-token-value');
      if (val) {
        try {
          await navigator.clipboard.writeText(val.textContent || '');
          setStatus('Token copied');
        } catch (e) {
          setStatus('Copy failed', true);
        }
      }
      return;
    }
    if (t.id === 'sl-signer-copy') {
      const val = document.getElementById('sl-signer-value');
      if (val) {
        try {
          await navigator.clipboard.writeText(val.textContent || '');
          setStatus('Signer copied');
        } catch (e) {
          setStatus('Copy failed', true);
        }
      }
      return;
    }

    const copy = t.getAttribute('data-copy');
    if (copy) {
      try {
        await navigator.clipboard.writeText(copy);
        setStatus('Copied short URL');
      } catch (e) {
        setStatus('Copy failed', true);
      }
      return;
    }

    const viewId = t.getAttribute('data-view-links');
    if (viewId) {
      try {
        await loadLinks(parseInt(viewId, 10), t.getAttribute('data-label') || '');
      } catch (e) {
        setStatus('Links: ' + e.message, true);
      }
      return;
    }

    const revokeId = t.getAttribute('data-revoke-bearer');
    if (revokeId) {
      if (!canOperate()) return;
      if (!window.confirm('Revoke bearer #' + revokeId + '?')) return;
      try {
        await fetchJson(apiUrl('revoke_bearer'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ bearer_id: parseInt(revokeId, 10) }),
        });
        if (selectedBearerId === parseInt(revokeId, 10)) {
          selectedBearerId = 0;
          const section = document.getElementById('sl-links-section');
          if (section) section.hidden = true;
        }
        await refresh();
      } catch (e) {
        setStatus('Revoke: ' + e.message, true);
      }
      return;
    }

    const revokeSignerId = t.getAttribute('data-revoke-signer');
    if (revokeSignerId) {
      if (!canOperate()) return;
      if (!window.confirm('Revoke signer #' + revokeSignerId + '?')) return;
      try {
        await fetchJson(apiUrl('revoke_signer'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ signer_id: parseInt(revokeSignerId, 10) }),
        });
        await refresh();
      } catch (e) {
        setStatus('Revoke signer: ' + e.message, true);
      }
    }
  });

  const permCb = document.getElementById('sl-permanent-cb');
  if (permCb) {
    permCb.addEventListener('change', syncPermanentUi);
    syncPermanentUi();
  }

  const mintPermCb = document.getElementById('sl-can-permanent');
  if (mintPermCb) {
    mintPermCb.addEventListener('change', syncMintPermanentUi);
    syncMintPermanentUi();
  }

  const mintForm = document.getElementById('sl-mint-form');
  if (mintForm) {
    mintForm.addEventListener('submit', async (ev) => {
      ev.preventDefault();
      if (!canOperate()) return;
      const fd = new FormData(mintForm);
      try {
        setStatus('Minting bearer…');
        const data = await fetchJson(apiUrl('mint_bearer'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            label: fd.get('label'),
            rate_limit_per_hour: parseInt(String(fd.get('rate_limit') || '1000'), 10),
            can_temporary: fd.get('can_temporary') === '1',
            can_permanent: fd.get('can_permanent') === '1',
            mint_signer: fd.get('mint_signer') === '1',
          }),
        });
        mintForm.reset();
        syncMintPermanentUi();
        showSecretModal('sl-token-modal', 'sl-token-value', data.token);
        if (data.signer_key) {
          showSecretModal('sl-signer-modal', 'sl-signer-value', data.signer_key);
        }
        await refresh();
      } catch (e) {
        setStatus('Mint: ' + e.message, true);
      }
    });
  }

  const mintSignerForm = document.getElementById('sl-mint-signer-form');
  if (mintSignerForm) {
    mintSignerForm.addEventListener('submit', async (ev) => {
      ev.preventDefault();
      if (!canOperate()) return;
      const fd = new FormData(mintSignerForm);
      try {
        const data = await fetchJson(apiUrl('mint_signer'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ label: fd.get('label') }),
        });
        mintSignerForm.reset();
        showSecretModal('sl-signer-modal', 'sl-signer-value', data.signer_key);
        await refresh();
      } catch (e) {
        setStatus('Mint signer: ' + e.message, true);
      }
    });
  }

  const shortenForm = document.getElementById('sl-shorten-form');
  if (shortenForm) {
    shortenForm.addEventListener('submit', async (ev) => {
      ev.preventDefault();
      if (!canOperate()) return;
      const fd = new FormData(shortenForm);
      const permanent = fd.get('permanent') === '1';
      try {
        const payload = {
          bearer_id: parseInt(String(fd.get('bearer_id') || '0'), 10),
          url: fd.get('url'),
          ttl: permanent ? 0 : parseInt(String(fd.get('ttl') || '86400'), 10),
        };
        if (permanent) {
          payload.signer = fd.get('signer');
        }
        const data = await fetchJson(apiUrl('create_link'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payload),
        });
        if (data.link && data.link.short_url) {
          setStatus('Short URL: ' + data.link.short_url);
        }
        shortenForm.querySelector('[name="url"]').value = '';
        await refresh();
      } catch (e) {
        setStatus('Shorten: ' + e.message, true);
      }
    });
  }

  const purgeBtn = document.getElementById('sl-purge-btn');
  if (purgeBtn) {
    if (!canAdmin()) purgeBtn.hidden = true;
    purgeBtn.addEventListener('click', async () => {
      if (!canAdmin()) return;
      if (!window.confirm('Delete all expired links and audit rows older than 90 days?')) return;
      try {
        const data = await fetchJson(apiUrl('purge_expired'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({}),
        });
        setStatus('Purged links=' + (data.purged && data.purged.links) + ' audit=' + (data.purged && data.purged.audit));
        await refresh();
      } catch (e) {
        setStatus('Purge: ' + e.message, true);
      }
    });
  }

  ['sl-token-modal', 'sl-signer-modal'].forEach((id) => {
    const modal = document.getElementById(id);
    if (modal) {
      modal.addEventListener('click', (ev) => {
        if (ev.target === modal) hideModal(id);
      });
    }
  });
  document.addEventListener('keydown', (ev) => {
    if (ev.key === 'Escape') {
      hideModal('sl-token-modal');
      hideModal('sl-signer-modal');
    }
  });

  refresh();
})();
