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

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

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

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

  function setStatus(msg, isError) {
    const el = document.getElementById('ra-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) {
      throw new Error(data.error || ('HTTP ' + res.status));
    }
    return data;
  }

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

  function statusBadge(d) {
    const label = d.status_label || '';
    if (label === 'needs_whitelist') {
      return '<span class="tag-pill tag-pill--warn">Needs whitelist</span>';
    }
    if (label === 'whitelisted') {
      return '<span class="tag-pill">Whitelisted</span>';
    }
    if (label === 'stale') {
      return '<span class="muted">Stale</span>';
    }
    if (label === 'not_opted_in') {
      return '<span class="muted">Not opted in</span>';
    }
    return '<span class="muted">Polling</span>';
  }

  function deviceTitle(d) {
    const name = (d.device_display || '').trim();
    if (name) {
      return name;
    }
    const id = String(d.device_id || '');
    if (id.length > 14) {
      return id.slice(0, 8) + '…' + id.slice(-4);
    }
    return id;
  }

  function detailLines(d) {
    const lines = [];
    lines.push('Device ID: ' + (d.device_id || '—'));
    if (d.device_display) {
      lines.push('Name: ' + d.device_display);
    }
    if (d.manufacturer || d.model) {
      lines.push('Hardware: ' + [d.manufacturer, d.model].filter(Boolean).join(' '));
    }
    if (d.os_release || d.sdk_int) {
      lines.push(
        'Android: ' +
          [d.os_release || '', d.sdk_int ? 'SDK ' + d.sdk_int : ''].filter(Boolean).join(' · ')
      );
    }
    lines.push('App version: ' + (d.app_version || '—'));
    lines.push('Opt-in mode: ' + (d.opt_in_mode || 'none'));
    lines.push('Last seen: ' + (d.last_seen_at || '—'));
    if (d.notes) {
      lines.push('Notes: ' + d.notes);
    }
    if (d.issue_count != null) {
      lines.push('Linked issues: ' + d.issue_count);
    }
    if (d.graph_session_count != null) {
      lines.push('Graph sessions: ' + d.graph_session_count);
    }
    return lines;
  }

  function detailLinks(d) {
    const links = d.links || [];
    if (!links.length) {
      return '';
    }
    let html = '<div class="ra-detail-links">';
    links.forEach((link) => {
      html +=
        '<a class="btn btn-sm" href="' +
        esc(link.href) +
        '">' +
        esc(link.label) +
        '</a> ';
    });
    html += '</div>';
    return html;
  }

  function bindRaTree(root) {
    root.querySelectorAll('.report-tree-toggle').forEach((btn) => {
      btn.addEventListener('click', (e) => {
        e.stopPropagation();
        const id = btn.getAttribute('aria-controls');
        const briefRow = id ? document.getElementById(id) : null;
        const row = btn.closest('.report-row');
        if (!briefRow || !row) return;
        const open = briefRow.hidden;
        briefRow.hidden = !open;
        btn.setAttribute('aria-expanded', open ? 'true' : 'false');
        row.classList.toggle('report-row--open', open);
      });
    });
  }

  function renderDevices(devices) {
    const tbody = document.getElementById('ra-devices-tbody');
    if (!tbody) return;
    if (!devices || !devices.length) {
      tbody.innerHTML =
        '<tr><td colspan="7" class="muted">No devices have polled yet. Enable remote access on a device (dev settings) and wait for the next poll.</td></tr>';
      return;
    }
    let html = '';
    devices.forEach((d, i) => {
      const rowKey = 'ra-' + i;
      const briefId = 'ra-brief-' + rowKey;
      const wl = Number(d.whitelisted) === 1;
      const canOpen = canOperate() && wl && (d.opt_in_mode === 'wireguard' || d.opt_in_mode === 'rssh');
      const openDisabled = canOpen ? '' : ' disabled title="Whitelist device and wait for WireGuard/RSSH opt-in poll"';
      const wlDisabled = canAdmin() ? '' : ' disabled';
      const rowClass =
        'report-row' + (d.needs_whitelist ? ' ra-device-row--needs-wl' : '');
      html += '<tr class="' + rowClass + '">';
      html +=
        '<td class="report-tree-cell"><button type="button" class="report-tree-toggle" aria-expanded="false" aria-controls="' +
        briefId +
        '" title="Show device details"><span class="report-tree-arrow" aria-hidden="true"></span></button></td>';
      html +=
        '<td><code class="ra-device-id" title="' +
        esc(d.device_id) +
        '">' +
        esc(deviceTitle(d)) +
        '</code></td>';
      html += '<td>' + statusBadge(d) + '</td>';
      html += '<td>' + esc(d.opt_in_mode || 'none') + '</td>';
      html += '<td>' + esc(d.last_seen_at || '—') + '</td>';
      html += '<td>' + esc(d.app_version || '—') + '</td>';
      html +=
        '<td class="ra-device-actions">' +
        '<button type="button" class="btn btn-sm btn-primary"' +
        openDisabled +
        ' data-open-session="' +
        esc(d.device_id) +
        '">Open session</button> ' +
        '<button type="button" class="btn btn-sm"' +
        wlDisabled +
        ' data-toggle-wl="' +
        esc(d.device_id) +
        '" data-wl="' +
        (wl ? '0' : '1') +
        '">' +
        (wl ? 'Revoke WL' : 'Whitelist') +
        '</button> ' +
        '<button type="button" class="btn btn-sm" data-copy-id="' +
        esc(d.device_id) +
        '">Copy ID</button>' +
        '</td>';
      html += '</tr>';

      html +=
        '<tr class="report-brief-row" id="' +
        briefId +
        '" hidden><td colspan="7" class="report-brief-cell"><div class="report-brief-panel"><div class="report-brief">';
      detailLines(d).forEach((line) => {
        html += '<p>' + esc(line) + '</p>';
      });
      html += detailLinks(d);
      html += '</div></div></td></tr>';
    });
    tbody.innerHTML = html;
    bindRaTree(tbody);
  }

  function renderSessions(active, inactive) {
    const aBody = document.getElementById('ra-active-tbody');
    const iBody = document.getElementById('ra-inactive-tbody');
    if (aBody) {
      aBody.innerHTML = '';
      if (!active || !active.length) {
        aBody.innerHTML = '<tr><td colspan="6" class="muted">No pending or active sessions.</td></tr>';
      }
      (active || []).forEach((s) => {
        const tr = document.createElement('tr');
        const closeBtn = canOperate()
          ? '<button type="button" class="btn btn-sm" data-close-session="' + esc(s.session_id) + '" data-device="' + esc(s.device_id) + '">Close</button>'
          : '';
        tr.innerHTML =
          '<td><code>' + esc(s.session_id) + '</code></td>' +
          '<td><code>' + esc(s.device_id) + '</code></td>' +
          '<td>' + esc(s.status) + '</td>' +
          '<td>' + esc(s.tunnel) + '</td>' +
          '<td>' + esc(s.endpoint || '—') + '</td>' +
          '<td>' + closeBtn + '</td>';
        aBody.appendChild(tr);
      });
    }
    if (iBody) {
      iBody.innerHTML = '';
      (inactive || []).forEach((s) => {
        const tr = document.createElement('tr');
        tr.innerHTML =
          '<td><code>' + esc(s.session_id) + '</code></td>' +
          '<td><code>' + esc(s.device_id) + '</code></td>' +
          '<td>' + esc(s.status) + '</td>' +
          '<td>' + esc(s.closed_at || '—') + '</td>' +
          '<td>' + esc(s.close_reason || '—') + '</td>';
        iBody.appendChild(tr);
      });
      if (!inactive || !inactive.length) {
        iBody.innerHTML = '<tr><td colspan="5" class="muted">No closed sessions yet.</td></tr>';
      }
    }
  }

  function renderEvents(events) {
    const tbody = document.getElementById('ra-events-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    if (!events || !events.length) {
      tbody.innerHTML = '<tr><td colspan="4" class="muted">No audit events.</td></tr>';
      return;
    }
    (events || []).forEach((e) => {
      const tr = document.createElement('tr');
      tr.innerHTML =
        '<td>' + esc(e.created_at) + '</td>' +
        '<td><code>' + esc(e.device_id) + '</code></td>' +
        '<td>' + esc(e.action) + '</td>' +
        '<td>' + esc(e.reason || '—') + '</td>';
      tbody.appendChild(tr);
    });
  }

  let lastConfig = {};

  async function refresh() {
    setStatus('Loading…');
    try {
      const data = await fetchJson(apiUrl('dashboard'));
      lastConfig = data.config || {};
      renderDevices(data.devices);
      renderSessions(data.active_sessions, data.inactive_sessions);
      renderEvents(data.recent_events);
      const ep = lastConfig.wg_endpoint ? ' · WG ' + lastConfig.wg_endpoint : '';
      setStatus('Updated ' + new Date().toLocaleTimeString() + ep);
    } catch (e) {
      setStatus('Failed: ' + e.message, true);
    }
  }

  document.addEventListener('click', async (ev) => {
    const t = ev.target;
    if (!(t instanceof HTMLElement)) return;
    if (t.closest('.report-tree-toggle, .ra-detail-links a')) {
      return;
    }
    const copyId = t.getAttribute('data-copy-id');
    if (copyId) {
      try {
        await navigator.clipboard.writeText(copyId);
        setStatus('Copied device ID');
      } catch (e) {
        setStatus('Copy failed', true);
      }
      return;
    }
    const openId = t.getAttribute('data-open-session');
    if (openId) {
      if (!canOperate()) return;
      try {
        setStatus('Opening session for ' + openId + '…');
        await fetchJson(apiUrl('open_session'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ device_id: openId }),
        });
        setStatus('Session opened — device will connect on next poll (≤7 min)');
        await refresh();
      } catch (e) {
        setStatus('Open session: ' + e.message, true);
      }
      return;
    }
    const closeId = t.getAttribute('data-close-session');
    if (closeId) {
      if (!canOperate()) return;
      try {
        await fetchJson(apiUrl('close_session'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            session_id: closeId,
            device_id: t.getAttribute('data-device') || '',
          }),
        });
        await refresh();
      } catch (e) {
        setStatus('Close session: ' + e.message, true);
      }
      return;
    }
    const wlDevice = t.getAttribute('data-toggle-wl');
    if (wlDevice) {
      if (!canAdmin()) return;
      try {
        await fetchJson(apiUrl('whitelist'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            device_id: wlDevice,
            whitelisted: t.getAttribute('data-wl') === '1',
          }),
        });
        await refresh();
      } catch (e) {
        setStatus('Whitelist: ' + e.message, true);
      }
    }
  });

  const form = document.getElementById('ra-whitelist-form');
  if (form) {
    if (!canAdmin()) {
      form.hidden = true;
    }
    form.addEventListener('submit', async (ev) => {
      ev.preventDefault();
      if (!canAdmin()) return;
      const fd = new FormData(form);
      try {
        await fetchJson(apiUrl('whitelist'), {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            device_id: fd.get('device_id'),
            notes: fd.get('notes'),
            whitelisted: true,
          }),
        });
        form.reset();
        await refresh();
      } catch (e) {
        setStatus('Whitelist add: ' + e.message, true);
      }
    });
  }

  refresh();
  setInterval(refresh, 30000);
})();
