/* ============================================================
   page-screenshot.jsx — Captures admin management (admin only)
                       + silent user-side auto-capture poller
   ============================================================ */
const { useState, useEffect } = React;

/* ---------- USER SIDE: silent auto-capture poller ---------- */
// Runs in EVERY logged-in browser session. Polls /api/screenshot/pending
// every 60s; for any approved capture, immediately calls
// navigator.mediaDevices.getDisplayMedia() — the browser will prompt the
// user to pick a screen/window (per Chrome/Edge/Firefox/Safari spec, this
// permission cannot be bypassed by web technology). After the user picks,
// a single frame is grabbed + uploaded.
function startCaptureAutoPoller() {
  if (window.__captureAutoPollerStarted) return;
  window.__captureAutoPollerStarted = true;

  const SEEN = new Set();
  const tick = async () => {
    try {
      const r = await fetch('/api/screenshot/pending', { credentials: 'include' });
      if (!r.ok) return;
      const data = await r.json();
      for (const cap of (data.items || [])) {
        if (cap.status !== 'approved' && cap.status !== 'requested') continue;
        if (SEEN.has(cap.id)) continue;
        SEEN.add(cap.id);
        await captureAndUpload(cap.id);
      }
    } catch (_) {}
  };
  tick();
  setInterval(tick, 60_000);
}

async function captureAndUpload(captureId) {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
    return;
  }
  let stream;
  try {
    stream = await navigator.mediaDevices.getDisplayMedia({
      video: { displaySurface: 'monitor', frameRate: 1 }
    });
  } catch (e) {
    // User dismissed the browser prompt; nothing to do.
    return;
  }
  try {
    const track = stream.getVideoTracks()[0];
    let bitmap;
    try {
      const imageCapture = new ImageCapture(track);
      bitmap = await imageCapture.grabFrame();
    } catch (_) {
      // Safari fallback — draw the video element to canvas
      const video = document.createElement('video');
      video.srcObject = stream; await video.play();
      await new Promise(r => setTimeout(r, 200));
      bitmap = video;  // canvas.drawImage accepts video element
    }
    const canvas = document.createElement('canvas');
    canvas.width  = bitmap.width  || (bitmap.videoWidth  || 1920);
    canvas.height = bitmap.height || (bitmap.videoHeight || 1080);
    canvas.getContext('2d').drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    track.stop();

    const blob = await new Promise(r => canvas.toBlob(r, 'image/png'));
    const buf  = await blob.arrayBuffer();
    const u8   = new Uint8Array(buf);
    let bin = ''; const CHUNK = 0x8000;
    for (let i = 0; i < u8.length; i += CHUNK) {
      bin += String.fromCharCode.apply(null, u8.subarray(i, i + CHUNK));
    }
    const b64 = btoa(bin);
    await fetch(`/api/screenshot/${captureId}/upload`, {
      method: 'POST', credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ image_b64: b64, mime: 'image/png' }),
    });
  } finally {
    try { stream.getTracks().forEach(t => t.stop()); } catch (_) {}
  }
}

// Kick off the poller as soon as this file loads.
try { startCaptureAutoPoller(); } catch (_) {}

/* ---------- ADMIN SIDE: Captures management ---------- */
function CapturesAdminPage() {
  const D = window.STATUS_DATA || {};
  const meRole = String((D.ME || {}).org_role || '').toLowerCase();
  const isAdmin = meRole === 'admin' || meRole === 'owner';
  const employees = D.EMPLOYEES || [];

  const [captures, setCaptures] = useState([]);
  const [loading, setLoading]   = useState(false);
  const [targetId, setTargetId] = useState(employees[0]?.id || null);
  const [note, setNote]         = useState('');
  const [filter, setFilter]     = useState('all');
  const [imageOf, setImageOf]   = useState(null);  // capture row for preview
  const toast = useToast ? useToast() : { push: () => {} };

  const load = async () => {
    setLoading(true);
    try {
      const url = '/api/screenshot/captures' + (filter !== 'all' ? `?status=${filter}` : '');
      const r = await fetch(url, { credentials: 'include' });
      if (r.ok) {
        const d = await r.json();
        setCaptures(d.items || []);
      }
    } catch (_) {}
    finally { setLoading(false); }
  };

  useEffect(() => { if (isAdmin) load(); }, [filter]);

  const requestCapture = async () => {
    if (!targetId) {
      toast.push({ msg: 'Pick a user', kind: 'warn' });
      return;
    }
    try {
      const r = await fetch('/api/screenshot/request', {
        method: 'POST', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ user_id: targetId, note }),
      });
      if (!r.ok) throw new Error(`${r.status}`);
      toast.push({ msg: 'Capture requested (auto-approved). Their browser will prompt to share screen.', kind: 'ok' });
      setNote('');
      await load();
    } catch (e) {
      toast.push({ msg: 'Request failed: ' + e.message, kind: 'err' });
    }
  };

  if (!isAdmin) {
    return (
      <div className="page">
        <div className="card" style={{ padding: 16 }}>
          <strong>Admin only.</strong> Screen capture management is restricted to administrators.
        </div>
      </div>
    );
  }

  const empById = Object.fromEntries(employees.map(e => [e.id, e]));

  return (
    <div className="page">
      <PageHeader
        title="Screen captures"
        meta="Admin-only · auto-approved · captures upload when target browser is open"
        right={<Refresh onClick={load} loading={loading} />}
      />

      {/* Request card */}
      <div className="card" style={{ marginBottom: 16 }}>
        <SectionHeader
          title="Request capture"
          tip="Admin requests are auto-approved server-side. The target user's open browser session will poll for pending captures every 60 seconds and immediately fire the native getDisplayMedia browser permission prompt — that prompt is non-bypassable and lets the user pick which screen/window to share. If the user dismisses the prompt the capture stays unfulfilled."
          sub="No user consent UI — fires immediately"
        />
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <select className="sel" value={targetId || ''} onChange={e => setTargetId(Number(e.target.value))}
            style={{ minWidth: 200 }}>
            {employees.map(e => <option key={e.id} value={e.id}>{e.display_name}</option>)}
          </select>
          <input className="inp" placeholder="Note (visible in audit log)"
            value={note} onChange={e => setNote(e.target.value)}
            style={{ flex: 1, minWidth: 200 }} />
          <button className="btn btn-pri" onClick={requestCapture}>Request capture</button>
        </div>
      </div>

      {/* Captures list */}
      <div className="card">
        <SectionHeader
          title="Capture history"
          tip="Every capture request + lifecycle event. Status: requested → approved (auto) → captured (after browser upload) → deleted (after retention). Click thumbnails for full image."
          sub={`${captures.length} captures`}
          right={
            <select className="sel" value={filter} onChange={e => setFilter(e.target.value)}
              style={{ fontSize: 12 }}>
              <option value="all">All</option>
              <option value="approved">Pending capture</option>
              <option value="captured">Captured</option>
              <option value="denied">Denied</option>
              <option value="deleted">Deleted (retention)</option>
            </select>
          }
        />
        <table className="t" style={{ fontSize: 12 }}>
          <thead><tr>
            <th>User</th><th>Trigger</th><th>Requested</th><th>Captured</th>
            <th>Status</th><th>Region</th><th>Retention</th><th>Note</th><th></th>
          </tr></thead>
          <tbody>
            {captures.length === 0 && !loading ? (
              <tr><td colSpan={9} className="muted" style={{ textAlign: 'center', padding: 16 }}>No captures yet.</td></tr>
            ) : captures.map(c => (
              <tr key={c.id}>
                <td>{(empById[c.user_id] || {}).display_name || `#${c.user_id}`}</td>
                <td>{c.trigger}</td>
                <td className="mono" style={{ fontSize: 11 }}>{c.requested_at ? new Date(c.requested_at).toLocaleString() : '—'}</td>
                <td className="mono" style={{ fontSize: 11 }}>{c.captured_at ? new Date(c.captured_at).toLocaleString() : '—'}</td>
                <td>
                  <span className={`badge ${
                    c.status === 'captured' ? 'ok' :
                    c.status === 'denied' || c.status === 'deleted' ? 'err' :
                    'mute'
                  }`}>{c.status}</span>
                </td>
                <td className="mono" style={{ fontSize: 11 }}>{c.region_code_at_request || '—'}</td>
                <td className="mono" style={{ fontSize: 11 }}>{c.retention_until ? c.retention_until.slice(0, 10) : '—'}</td>
                <td className="muted">{c.note || ''}</td>
                <td>
                  {c.has_image && (
                    <button className="btn btn-ghost" style={{ padding: '2px 8px', fontSize: 11 }}
                      onClick={() => setImageOf(c)}>View</button>
                  )}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {imageOf && (
        <div onClick={() => setImageOf(null)} style={{
          position: 'fixed', inset: 0, background: 'rgba(0,0,0,.8)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999,
        }}>
          <img src={`/api/screenshot/captures/${imageOf.id}/image`}
            alt={`Capture #${imageOf.id}`}
            style={{ maxWidth: '92vw', maxHeight: '92vh', boxShadow: '0 0 32px rgba(0,0,0,.8)' }}
            onClick={e => e.stopPropagation()} />
        </div>
      )}
    </div>
  );
}

window.CapturesAdminPage = CapturesAdminPage;
