// admin-recordings.jsx — Recordings tab.
//
// Two kinds of recordings live here:
//  1. "Record a meeting" (external): paste a Google Meet / Zoom link → the
//     mastery-recorder bot joins the call, records the audio, and uploads it to
//     Cloudflare R2. Listed via admin_list_external_recordings; started/stopped/
//     played through the /api/recording/*-external relays (which sign + forward
//     to the recorder service so R2 + proxy creds never touch the browser).
//  2. Lesson audio (Daily in-tab capture): the original recordings, keyed off
//     bookings.audio_storage_path via admin_list_recordings, played from a
//     5-min Supabase Storage signed URL.
//
// Public on window: AdminRecordings.

(function () {
  'use strict';

  const fmtDateTime = (iso) => {
    if (!iso) return '—';
    try {
      const d = new Date(iso);
      return d.toLocaleString(undefined, {
        month: 'short', day: 'numeric',
        hour: 'numeric', minute: '2-digit',
      });
    } catch (_) { return iso; }
  };

  const fmtDuration = (sec) => {
    if (!sec || sec < 0) return '—';
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}m ${String(s).padStart(2, '0')}s`;
  };

  const fmtBytes = (bytes) => {
    if (bytes == null) return '—';
    const mb = bytes / (1024 * 1024);
    if (mb < 1) return (bytes / 1024).toFixed(0) + ' KB';
    return mb.toFixed(1) + ' MB';
  };

  const statusBadge = (s) => {
    const map = {
      uploaded:  { bg: 'oklch(94% 0.07 150)', fg: 'oklch(32% 0.13 150)', label: 'Uploaded' },
      recording: { bg: 'oklch(94% 0.07 80)',  fg: 'oklch(38% 0.13 80)',  label: 'Recording' },
      failed:    { bg: 'oklch(94% 0.08 25)',  fg: 'oklch(42% 0.13 25)',  label: 'Failed' },
    };
    const c = map[s] || { bg: 'oklch(94% 0.01 265)', fg: 'oklch(38% 0.04 265)', label: s || '—' };
    return (
      <span style={{
        display: 'inline-block', padding: '3px 9px', borderRadius: 20,
        background: c.bg, color: c.fg, fontWeight: 600, fontSize: 11,
        fontFamily: "'Plus Jakarta Sans', sans-serif",
      }}>{c.label}</span>
    );
  };

  const sourceBadge = (src) => {
    const map = {
      meet: { bg: 'oklch(93% 0.05 250)', fg: 'oklch(40% 0.15 265)', label: 'Google Meet' },
      zoom: { bg: 'oklch(93% 0.06 285)', fg: 'oklch(38% 0.17 285)', label: 'Zoom' },
    };
    const c = map[src] || { bg: 'oklch(94% 0.01 265)', fg: 'oklch(40% 0.04 265)', label: src || '—' };
    return (
      <span style={{
        display: 'inline-block', padding: '2px 8px', borderRadius: 20,
        background: c.bg, color: c.fg, fontWeight: 600, fontSize: 11,
        fontFamily: "'Plus Jakarta Sans', sans-serif",
      }}>{c.label}</span>
    );
  };

  // Authed POST to an /api route. Throws on !ok with the server's error message.
  const postJson = async (path, body) => {
    const { data: sess } = await window.supa.auth.getSession();
    const jwt = sess?.session?.access_token;
    if (!jwt) throw new Error('Not signed in.');
    const r = await fetch(path, {
      method: 'POST',
      headers: { 'content-type': 'application/json', Authorization: 'Bearer ' + jwt },
      body: JSON.stringify(body),
    });
    const j = await r.json().catch(() => ({}));
    if (!r.ok || !j.ok) throw new Error(j.error || `HTTP ${r.status}`);
    return j;
  };

  // ── External meeting recorder: paste a link → bot joins → records → play ──

  const ExternalRow = ({ rec, onPlay, onStop, onDelete, onToggleNotes, playingId, playUrl, playErr, stoppingId, deletingId, notesOpen }) => {
    const isPlaying = playingId === rec.id;
    const title = rec.label || rec.meeting_url || rec.id;
    const ts = rec.transcript_status || null;
    const hasNotes = !!(rec.ai_summary || rec.transcript);
    return (
      <div style={{
        background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 10,
        padding: '12px 16px', marginBottom: 10,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
          <div style={{ minWidth: 128 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: 'oklch(14% 0.04 265)' }}>
              {fmtDateTime(rec.started_at)}
            </div>
            <div style={{ marginTop: 3 }}>{sourceBadge(rec.source)}</div>
          </div>

          <div style={{ flex: 1, minWidth: 200 }}>
            <div style={{ fontSize: 14, color: 'oklch(20% 0.04 265)', fontWeight: 500, wordBreak: 'break-word' }}>{title}</div>
            {rec.label && rec.meeting_url && (
              <div style={{ fontSize: 11, color: 'oklch(58% 0.03 265)', wordBreak: 'break-all' }}>{rec.meeting_url}</div>
            )}
            {rec.error && (
              <div style={{ fontSize: 11, color: 'oklch(42% 0.13 25)', marginTop: 3 }}>
                {String(rec.error).slice(0, 200)}
              </div>
            )}
          </div>

          <div style={{ fontSize: 12, color: 'oklch(40% 0.04 265)', minWidth: 64, textAlign: 'right' }}>
            {fmtDuration(rec.duration_sec)}
          </div>
          <div style={{ fontSize: 12, color: 'oklch(40% 0.04 265)', minWidth: 64, textAlign: 'right' }}>
            {fmtBytes(rec.file_size_bytes)}
          </div>

          <div style={{ minWidth: 86 }}>{statusBadge(rec.status)}</div>

          {rec.status === 'recording' ? (
            <button
              type="button"
              disabled={stoppingId === rec.id}
              onClick={() => onStop(rec.id)}
              style={{
                padding: '7px 14px', borderRadius: 8, border: 'none',
                background: 'oklch(55% 0.16 25)', color: '#fff',
                fontWeight: 600, fontSize: 12, cursor: stoppingId === rec.id ? 'wait' : 'pointer',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
              }}
            >{stoppingId === rec.id ? 'Stopping…' : 'Stop'}</button>
          ) : (
            <button
              type="button"
              disabled={rec.status !== 'uploaded'}
              onClick={() => onPlay(rec.id)}
              style={{
                padding: '7px 14px', borderRadius: 8, border: 'none',
                background: rec.status === 'uploaded' ? 'oklch(38% 0.12 265)' : 'oklch(92% 0.01 265)',
                color: rec.status === 'uploaded' ? '#fff' : 'oklch(60% 0.03 265)',
                fontWeight: 600, fontSize: 12,
                cursor: rec.status === 'uploaded' ? 'pointer' : 'not-allowed',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
              }}
            >{isPlaying ? 'Stop' : 'Play'}</button>
          )}

          {rec.status === 'uploaded' && (
            <button
              type="button"
              onClick={() => onToggleNotes(rec.id)}
              style={{
                padding: '7px 12px', borderRadius: 8,
                border: '1px solid oklch(86% 0.03 265)',
                background: notesOpen ? 'oklch(96% 0.02 265)' : '#fff',
                color: 'oklch(38% 0.08 265)', fontWeight: 600, fontSize: 12, cursor: 'pointer',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}
            >
              {notesOpen ? 'Hide notes' : 'Summary & transcript'}
              {hasNotes && !notesOpen && (
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'oklch(60% 0.15 150)' }} />
              )}
            </button>
          )}

          {rec.status !== 'recording' && (
            <button
              type="button"
              disabled={deletingId === rec.id}
              onClick={() => onDelete(rec.id)}
              title="Delete this recording"
              style={{
                padding: '7px 12px', borderRadius: 8,
                border: '1px solid oklch(82% 0.06 25)', background: '#fff',
                color: 'oklch(48% 0.16 25)', fontWeight: 600, fontSize: 12,
                cursor: deletingId === rec.id ? 'wait' : 'pointer',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
              }}
            >{deletingId === rec.id ? 'Deleting…' : 'Delete'}</button>
          )}
        </div>

        {isPlaying && (
          <div style={{ marginTop: 10 }}>
            {playErr && (
              <div style={{ fontSize: 12, color: 'oklch(42% 0.13 25)' }}>Couldn't load audio: {playErr}</div>
            )}
            {playUrl && (
              <audio src={playUrl} controls autoPlay style={{ width: '100%', maxWidth: 600 }} />
            )}
            {!playUrl && !playErr && (
              <div style={{ fontSize: 12, color: 'oklch(58% 0.03 265)' }}>Loading…</div>
            )}
          </div>
        )}

        {notesOpen && (
          <div style={{ marginTop: 12, borderTop: '1px solid oklch(94% 0.01 265)', paddingTop: 12 }}>
            {ts === 'processing' && (
              <div style={{ fontSize: 13, color: 'oklch(45% 0.06 265)' }}>
                Transcribing the audio and writing the summary… hit Refresh in a moment.
              </div>
            )}
            {ts === 'error' && (
              <div style={{ fontSize: 13, color: 'oklch(42% 0.13 25)' }}>
                Couldn't transcribe this recording{rec.transcript_error ? `: ${String(rec.transcript_error).slice(0, 240)}` : '.'}
              </div>
            )}
            {ts === 'skipped' && (
              <div style={{ fontSize: 13, color: 'oklch(58% 0.03 265)' }}>
                Transcription isn't turned on for the recorder yet.
              </div>
            )}
            {hasNotes && (
              <React.Fragment>
                {rec.ai_summary && (
                  <div style={{ marginBottom: rec.transcript ? 14 : 0 }}>
                    <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.4, color: 'oklch(48% 0.06 265)', marginBottom: 6 }}>Summary</div>
                    <div style={{ fontSize: 14, lineHeight: 1.6, color: 'oklch(22% 0.06 265)', whiteSpace: 'pre-wrap' }}>{rec.ai_summary}</div>
                  </div>
                )}
                {rec.transcript && (
                  <div>
                    <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.4, color: 'oklch(48% 0.06 265)', marginBottom: 6 }}>Full transcript</div>
                    <div style={{ fontSize: 13, lineHeight: 1.55, color: 'oklch(30% 0.04 265)', whiteSpace: 'pre-wrap', maxHeight: 320, overflow: 'auto', padding: 12, background: 'oklch(97% 0.005 265)', borderRadius: 8 }}>{rec.transcript}</div>
                  </div>
                )}
              </React.Fragment>
            )}
            {!hasNotes && ts === 'done' && (
              <div style={{ fontSize: 13, color: 'oklch(58% 0.03 265)' }}>No speech was detected in this recording.</div>
            )}
            {!hasNotes && !ts && (
              <div style={{ fontSize: 13, color: 'oklch(58% 0.03 265)' }}>No transcript yet for this recording.</div>
            )}
          </div>
        )}
      </div>
    );
  };

  const ExternalRecordings = () => {
    const [rows, setRows]           = React.useState(null);  // null = loading
    const [err, setErr]             = React.useState('');
    const [link, setLink]           = React.useState('');
    const [label, setLabel]         = React.useState('');
    const [submitting, setSubmitting] = React.useState(false);
    const [msg, setMsg]             = React.useState('');
    const [formErr, setFormErr]     = React.useState('');
    const [playingId, setPlayingId] = React.useState(null);
    const [playUrl, setPlayUrl]     = React.useState(null);
    const [playErr, setPlayErr]     = React.useState('');
    const [stoppingId, setStoppingId] = React.useState(null);
    const [deletingId, setDeletingId] = React.useState(null);
    const [notesId, setNotesId]       = React.useState(null);
    const onToggleNotes = (id) => setNotesId((cur) => (cur === id ? null : id));

    const load = React.useCallback(async () => {
      setErr('');
      try {
        const { data, error } = await window.supa.rpc('admin_list_external_recordings', { p_limit: 200 });
        if (error) throw error;
        setRows(data || []);
      } catch (e) {
        setErr(e.message || 'Could not load meeting recordings.');
        setRows([]);
      }
    }, []);

    React.useEffect(() => { load(); }, [load]);

    const onSubmit = async (e) => {
      e.preventDefault();
      setMsg(''); setFormErr('');
      const meetingUrl = link.trim();
      if (!/^https?:\/\//i.test(meetingUrl)) {
        setFormErr('Paste a meeting link — a Google Meet or Zoom URL.');
        return;
      }
      setSubmitting(true);
      try {
        const j = await postJson('/api/recording/download', {
          op: 'start', meeting_url: meetingUrl, label: label.trim(),
        });
        const where = j.platform === 'zoom' ? 'Zoom' : 'Google Meet';
        setMsg(`Bot is joining the ${where} meeting. Admit "Meeting Notes" when it asks to be let in — then it records on its own.`);
        setLink(''); setLabel('');
        load();
      } catch (e2) {
        setFormErr(e2.message || String(e2));
      } finally {
        setSubmitting(false);
      }
    };

    const onPlay = async (id) => {
      if (playingId === id) { setPlayingId(null); setPlayUrl(null); setPlayErr(''); return; }
      setPlayingId(id); setPlayUrl(null); setPlayErr('');
      try {
        const j = await postJson('/api/recording/download', { op: 'download', recording_id: id });
        setPlayUrl(j.url);
      } catch (e) {
        setPlayErr(e.message || String(e));
      }
    };

    const onStop = async (id) => {
      setStoppingId(id); setMsg(''); setFormErr('');
      try {
        await postJson('/api/recording/download', { op: 'stop', recording_id: id });
        setMsg('Stopping — the audio finishes uploading in a few seconds. Hit Refresh to see it.');
      } catch (e) {
        setFormErr(e.message || String(e));
      } finally {
        setStoppingId(null);
      }
    };

    const onDelete = async (id) => {
      const ok = window.confirm('Delete this recording? This permanently removes the stored audio and cannot be undone.');
      if (!ok) return;
      setDeletingId(id); setMsg(''); setFormErr('');
      try {
        await postJson('/api/recording/download', { op: 'delete', recording_id: id });
        if (playingId === id) { setPlayingId(null); setPlayUrl(null); }
        setMsg('Recording deleted.');
        await load();
      } catch (e) {
        setFormErr(e.message || String(e));
      } finally {
        setDeletingId(null);
      }
    };

    const inputStyle = {
      width: '100%', boxSizing: 'border-box', padding: '10px 12px',
      borderRadius: 8, border: '1px solid oklch(88% 0.01 265)',
      fontSize: 14, fontFamily: "'Plus Jakarta Sans', sans-serif",
      color: 'oklch(20% 0.04 265)', marginBottom: 10,
    };
    const total = (rows || []).length;

    return (
      <div style={{ marginBottom: 38 }}>
        <h1 style={{
          margin: 0, fontFamily: "'Plus Jakarta Sans', sans-serif",
          fontSize: 24, fontWeight: 700, color: 'oklch(14% 0.04 265)',
        }}>Record a meeting</h1>
        <div style={{ fontSize: 13, color: 'oklch(58% 0.03 265)', marginTop: 4, marginBottom: 16, maxWidth: 620 }}>
          Paste a Google Meet or Zoom link. A notetaker bot joins the call, records the audio, and stores it here.
          You'll admit "Meeting Notes" into the meeting once — then it runs on its own.
        </div>

        <form onSubmit={onSubmit} style={{
          background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 12,
          padding: 16, marginBottom: 12, maxWidth: 620,
        }}>
          <input
            type="url"
            value={link}
            onChange={(e) => setLink(e.target.value)}
            placeholder="https://meet.google.com/abc-defg-hij  or  https://zoom.us/j/123…"
            style={inputStyle}
            autoComplete="off"
          />
          <input
            type="text"
            value={label}
            onChange={(e) => setLabel(e.target.value)}
            placeholder="Label (optional) — e.g. Sarah's piano lesson"
            maxLength={200}
            style={{ ...inputStyle, marginBottom: 12 }}
          />
          <button
            type="submit"
            disabled={submitting}
            style={{
              padding: '10px 18px', borderRadius: 8, border: 'none',
              background: submitting ? 'oklch(70% 0.05 265)' : 'oklch(38% 0.12 265)',
              color: '#fff', fontWeight: 700, fontSize: 14,
              cursor: submitting ? 'wait' : 'pointer',
              fontFamily: "'Plus Jakarta Sans', sans-serif",
            }}
          >{submitting ? 'Sending the bot…' : 'Start recording'}</button>
        </form>

        {msg && (
          <div style={{
            padding: 12, borderRadius: 8, marginBottom: 14, maxWidth: 620,
            background: 'oklch(95% 0.05 150)', color: 'oklch(32% 0.13 150)', fontSize: 13,
          }}>{msg}</div>
        )}
        {formErr && (
          <div style={{
            padding: 12, borderRadius: 8, marginBottom: 14, maxWidth: 620,
            background: 'oklch(94% 0.08 25)', color: 'oklch(42% 0.13 25)', fontSize: 13,
          }}>{formErr}</div>
        )}

        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginTop: 22, marginBottom: 12, flexWrap: 'wrap', gap: 12 }}>
          <h2 style={{
            margin: 0, fontFamily: "'Plus Jakarta Sans', sans-serif",
            fontSize: 16, fontWeight: 700, color: 'oklch(24% 0.04 265)',
          }}>Meeting recordings {total ? `(${total})` : ''}</h2>
          <button
            type="button"
            onClick={load}
            style={{
              padding: '7px 14px', borderRadius: 8,
              border: '1px solid oklch(88% 0.01 265)', background: '#fff',
              fontWeight: 600, fontSize: 12, cursor: 'pointer',
              fontFamily: "'Plus Jakarta Sans', sans-serif", color: 'oklch(38% 0.04 265)',
            }}
          >Refresh</button>
        </div>

        {err && (
          <div style={{ padding: 12, borderRadius: 8, marginBottom: 14, background: 'oklch(94% 0.08 25)', color: 'oklch(42% 0.13 25)', fontSize: 13 }}>{err}</div>
        )}
        {rows === null && (
          <div style={{ color: 'oklch(58% 0.03 265)', fontSize: 13 }}>Loading…</div>
        )}
        {rows && rows.length === 0 && !err && (
          <div style={{ padding: '28px 20px', textAlign: 'center', color: 'oklch(58% 0.03 265)', background: '#fff', border: '1px dashed oklch(88% 0.01 265)', borderRadius: 10, fontSize: 13 }}>
            No meeting recordings yet. Paste a link above to record one.
          </div>
        )}
        {rows && rows.map((rec) => (
          <ExternalRow
            key={rec.id}
            rec={rec}
            onPlay={onPlay}
            onStop={onStop}
            onDelete={onDelete}
            onToggleNotes={onToggleNotes}
            playingId={playingId}
            playUrl={playingId === rec.id ? playUrl : null}
            playErr={playingId === rec.id ? playErr : ''}
            stoppingId={stoppingId}
            deletingId={deletingId}
            notesOpen={notesId === rec.id}
          />
        ))}
      </div>
    );
  };

  // ── Lesson audio (Daily in-tab capture) — original recordings list ──

  const RecordingRow = ({ rec, onPlay, playingId, presignedUrl, presignErr }) => {
    const isPlaying = playingId === rec.id;
    const pair = [rec.student_name, rec.instructor_name].filter(Boolean).join('  →  ') || '—';

    return (
      <div style={{
        background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 10,
        padding: '12px 16px', marginBottom: 10,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
          <div style={{ minWidth: 130 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: 'oklch(14% 0.04 265)' }}>
              {fmtDateTime(rec.started_at)}
            </div>
            <div style={{ fontSize: 11, color: 'oklch(58% 0.03 265)' }}>
              lesson {fmtDateTime(rec.booking_scheduled_at)}
            </div>
          </div>

          <div style={{ flex: 1, minWidth: 200 }}>
            <div style={{ fontSize: 14, color: 'oklch(20% 0.04 265)', fontWeight: 500 }}>{pair}</div>
            {rec.error && (
              <div style={{ fontSize: 11, color: 'oklch(42% 0.13 25)', marginTop: 3 }}>
                {String(rec.error).slice(0, 200)}
              </div>
            )}
          </div>

          <div style={{ fontSize: 12, color: 'oklch(40% 0.04 265)', minWidth: 80, textAlign: 'right' }}>
            {fmtDuration(rec.duration_sec)}
          </div>
          <div style={{ fontSize: 12, color: 'oklch(40% 0.04 265)', minWidth: 70, textAlign: 'right' }}>
            {fmtBytes(rec.file_size_bytes)}
          </div>

          <div style={{ minWidth: 90 }}>{statusBadge(rec.status)}</div>

          <button
            type="button"
            disabled={rec.status !== 'uploaded'}
            onClick={() => onPlay(rec.id)}
            style={{
              padding: '7px 14px', borderRadius: 8,
              border: 'none',
              background: rec.status === 'uploaded' ? 'oklch(38% 0.12 265)' : 'oklch(92% 0.01 265)',
              color: rec.status === 'uploaded' ? '#fff' : 'oklch(60% 0.03 265)',
              fontWeight: 600, fontSize: 12,
              cursor: rec.status === 'uploaded' ? 'pointer' : 'not-allowed',
              fontFamily: "'Plus Jakarta Sans', sans-serif",
            }}
          >
            {isPlaying ? 'Stop' : 'Play'}
          </button>
        </div>

        {isPlaying && (
          <div style={{ marginTop: 10 }}>
            {presignErr && (
              <div style={{ fontSize: 12, color: 'oklch(42% 0.13 25)' }}>
                Couldn't load audio: {presignErr}
              </div>
            )}
            {presignedUrl && (
              <audio
                src={presignedUrl}
                controls
                autoPlay
                style={{ width: '100%', maxWidth: 600 }}
              />
            )}
            {!presignedUrl && !presignErr && (
              <div style={{ fontSize: 12, color: 'oklch(58% 0.03 265)' }}>Loading…</div>
            )}
          </div>
        )}
      </div>
    );
  };

  const AdminRecordings = () => {
    const [rows, setRows]     = React.useState(null);  // null = loading
    const [err,  setErr]      = React.useState('');
    const [playingId, setPlayingId] = React.useState(null);
    const [presignedUrl, setPresignedUrl] = React.useState(null);
    const [presignErr, setPresignErr] = React.useState('');

    const load = React.useCallback(async () => {
      setErr('');
      try {
        // p_status is omitted: the v97/v98 RPC reads from
        // bookings.audio_storage_path so every returned row is implicitly
        // "uploaded". There's no Recording / Failed split to filter on yet
        // (that's a follow-up when we move to async R2 uploads with a real
        // recordings table). Returning all rows.
        const { data, error } = await window.supa.rpc('admin_list_recordings', {
          p_limit: 200,
        });
        if (error) throw error;
        setRows(data || []);
      } catch (e) {
        setErr(e.message || 'Could not load recordings.');
        setRows([]);
      }
    }, []);

    React.useEffect(() => { load(); }, [load]);

    const handlePlay = async (id) => {
      if (playingId === id) {
        setPlayingId(null);
        setPresignedUrl(null);
        setPresignErr('');
        return;
      }
      setPlayingId(id);
      setPresignedUrl(null);
      setPresignErr('');
      try {
        const { data: sess } = await window.supa.auth.getSession();
        const jwt = sess?.session?.access_token;
        if (!jwt) throw new Error('Not signed in.');
        const r = await fetch(`/api/recording/download?id=${encodeURIComponent(id)}`, {
          headers: { Authorization: 'Bearer ' + jwt },
        });
        const j = await r.json();
        if (!r.ok || !j.ok) throw new Error(j.error || `HTTP ${r.status}`);
        setPresignedUrl(j.url);
      } catch (e) {
        setPresignErr(e.message || String(e));
      }
    };

    const total = (rows || []).length;

    return (
      <div style={{ padding: '24px 28px', maxWidth: 1100 }}>
        {/* Paste-a-link meeting recorder (external Meet/Zoom → R2) */}
        <ExternalRecordings />

        <div style={{ borderTop: '1px solid oklch(92% 0.01 265)', paddingTop: 26 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6, flexWrap: 'wrap', gap: 12 }}>
            <div>
              <h1 style={{
                margin: 0, fontFamily: "'Plus Jakarta Sans', sans-serif",
                fontSize: 24, fontWeight: 700, color: 'oklch(14% 0.04 265)',
              }}>Lesson recordings</h1>
              <div style={{ fontSize: 13, color: 'oklch(58% 0.03 265)', marginTop: 4 }}>
                Audio captured from the instructor's browser tab during a Mastery lesson. Admin-only.
              </div>
            </div>
            <button
              type="button"
              onClick={load}
              style={{
                padding: '7px 14px', borderRadius: 8,
                border: '1px solid oklch(88% 0.01 265)', background: '#fff',
                fontWeight: 600, fontSize: 12, cursor: 'pointer',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
                color: 'oklch(38% 0.04 265)',
              }}
            >Refresh</button>
          </div>

          <div style={{
            fontSize: 12, color: 'oklch(58% 0.03 265)', margin: '12px 0 18px',
            fontFamily: "'Plus Jakarta Sans', sans-serif", fontWeight: 600,
          }}>
            {total} {total === 1 ? 'recording' : 'recordings'}
          </div>

          {err && (
            <div style={{
              padding: 12, borderRadius: 8, marginBottom: 14,
              background: 'oklch(94% 0.08 25)', color: 'oklch(42% 0.13 25)',
              fontSize: 13,
            }}>{err}</div>
          )}

          {rows === null && (
            <div style={{ color: 'oklch(58% 0.03 265)', fontSize: 13 }}>Loading recordings…</div>
          )}

          {rows && rows.length === 0 && !err && (
            <div style={{
              padding: '40px 20px', textAlign: 'center', color: 'oklch(58% 0.03 265)',
              background: '#fff', border: '1px dashed oklch(88% 0.01 265)', borderRadius: 10,
            }}>
              No lesson recordings yet.
            </div>
          )}

          {rows && rows.map(rec => (
            <RecordingRow
              key={rec.id}
              rec={rec}
              onPlay={handlePlay}
              playingId={playingId}
              presignedUrl={playingId === rec.id ? presignedUrl : null}
              presignErr={playingId === rec.id ? presignErr : ''}
            />
          ))}
        </div>
      </div>
    );
  };

  window.AdminRecordings = AdminRecordings;
})();
