// src/features/admin/ui/admin-masked-calls.jsx
//
// Admin tab:
//   1. Phone numbers — every saved teacher/student masked-call number with its
//      decrypted value + verified state. Admin can Approve (mark verified) or
//      Revoke. The fallback when self-serve OTP can't reach a country (e.g.
//      SMS carrier-filtered to Lebanon); an un-verified number won't bridge.
//   2. Monthly spend bar against the budget cap.
//   3. Recent masked_call_events log.
//
// Public: window.AdminMaskedCallsTab

(function () {
  function AdminMaskedCallsTab() {
    const [budget, setBudget]   = React.useState(null);
    const [events, setEvents]   = React.useState([]);
    const [phones, setPhones]   = React.useState({ instructors: [], students: [] });
    const [phonesErr, setPhonesErr] = React.useState('');
    const [err, setErr]         = React.useState('');
    const [loading, setLoading] = React.useState(true);

    // Reload ONLY the phone list — no global `loading` flag, so an Approve/
    // Revoke updates just that row instead of blanking the whole tab to
    // "Loading…". Used as the per-row onChanged callback.
    const reloadPhones = React.useCallback(async () => {
      try {
        const ph = await window.MaskedCalls.db.adminListPhones();
        setPhones(ph || { instructors: [], students: [] });
        setPhonesErr('');
      } catch (e) {
        setPhonesErr(e.message || String(e));
      }
    }, []);

    const refresh = React.useCallback(async () => {
      setLoading(true);
      // Phone list loads independently so a failure there can't blank the
      // budget bar / event log (and vice-versa).
      const phonesP = reloadPhones();
      try {
        const [b, ev] = await Promise.all([
          window.MaskedCalls.db.loadBudget(),
          window.MaskedCalls.db.listEvents({ limit: 100 }),
        ]);
        setBudget(b);
        setEvents(ev);
        setErr('');
      } catch (e) {
        setErr(e.message || String(e));
      } finally {
        setLoading(false);
      }
      await phonesP;
    }, [reloadPhones]);

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

    if (loading) {
      return <div style={{ padding: 24, fontFamily: "'Plus Jakarta Sans', sans-serif" }}>Loading…</div>;
    }
    if (err) {
      return (
        <div style={{ padding: 24, fontFamily: "'Plus Jakarta Sans', sans-serif" }}>
          <div style={{
            padding: 12, borderRadius: 6,
            background: 'oklch(96% 0.06 25)', color: 'oklch(40% 0.15 25)',
          }}>{err}</div>
        </div>
      );
    }

    const spendPct = budget ? Math.min(100, (budget.spendUsd / budget.budgetUsd) * 100) : 0;
    const overThreshold = budget ? budget.spendUsd >= budget.thresholdUsd : false;

    const rows = [...(phones.instructors || []), ...(phones.students || [])];

    return (
      <div style={{ padding: 24, fontFamily: "'Plus Jakarta Sans', sans-serif" }}>
        <div style={{
          display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
          gap: 12, marginBottom: 16, flexWrap: 'wrap',
        }}>
          <div>
            <div style={{ fontSize: 22, fontWeight: 700, color: 'oklch(22% 0.06 265)' }}>
              Masked calls
            </div>
            <div style={{ fontSize: 13, color: 'oklch(50% 0.03 265)' }}>
              One shared Twilio number. Voice only. ${budget?.budgetUsd.toFixed(2)}/month hard cap.
            </div>
          </div>
          <button onClick={refresh} type="button"
            style={{
              padding: '6px 12px', borderRadius: 6,
              border: '1px solid oklch(86% 0.02 265)', background: '#fff',
              cursor: 'pointer', fontSize: 13, color: 'oklch(35% 0.04 265)',
              fontFamily: 'inherit',
            }}
          >Refresh</button>
        </div>

        {/* Phone numbers / verification */}
        <div style={{
          background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 10,
          overflow: 'hidden', marginBottom: 20,
        }}>
          <div style={{
            padding: '12px 16px', borderBottom: '1px solid oklch(92% 0.01 265)',
          }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'oklch(28% 0.06 265)' }}>
              Phone numbers ({rows.length})
            </div>
            <div style={{ fontSize: 12, color: 'oklch(50% 0.03 265)', marginTop: 2 }}>
              Approve a number once you've confirmed it's really theirs. An unverified number
              will not connect on masked calls.
            </div>
          </div>
          {phonesErr ? (
            <div style={{ padding: 16, fontSize: 13, color: 'oklch(40% 0.15 25)' }}>{phonesErr}</div>
          ) : rows.length === 0 ? (
            <div style={{ padding: 24, textAlign: 'center', color: 'oklch(50% 0.03 265)', fontSize: 13 }}>
              No numbers saved yet.
            </div>
          ) : (
            <div style={{ overflowX: 'auto' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
                <thead style={{ background: 'oklch(98% 0.005 60)' }}>
                  <tr style={{ textAlign: 'left', color: 'oklch(45% 0.04 265)', fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                    <th style={{ padding: '8px 12px' }}>Who</th>
                    <th style={{ padding: '8px 12px' }}>Number</th>
                    <th style={{ padding: '8px 12px' }}>Status</th>
                    <th style={{ padding: '8px 12px' }}>Action</th>
                  </tr>
                </thead>
                <tbody>
                  {rows.map((row) => (
                    <PhoneRow
                      key={`${row.kind}:${row.kind === 'instructor' ? row.instructorId : row.userId}`}
                      row={row}
                      onChanged={reloadPhones}
                    />
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>

        {/* Budget bar */}
        <div style={{
          background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 10,
          padding: 16, marginBottom: 20,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'oklch(28% 0.06 265)' }}>
              This month
            </div>
            <div style={{ fontSize: 14, color: 'oklch(36% 0.04 265)' }}>
              ${budget?.spendUsd.toFixed(2)} / ${budget?.budgetUsd.toFixed(2)}
            </div>
          </div>
          <div style={{
            height: 10, background: 'oklch(94% 0.01 265)', borderRadius: 5, overflow: 'hidden',
          }}>
            <div style={{
              width: `${spendPct}%`, height: '100%',
              background: overThreshold ? 'oklch(60% 0.20 25)' : 'oklch(60% 0.18 250)',
              transition: 'width 200ms',
            }} />
          </div>
          <div style={{ marginTop: 10, fontSize: 12, color: 'oklch(50% 0.03 265)' }}>
            Status: {budget?.enabled
              ? <span style={{ color: 'oklch(36% 0.13 145)', fontWeight: 600 }}>Active</span>
              : <span style={{ color: 'oklch(40% 0.15 25)', fontWeight: 600 }}>Paused (budget cap)</span>
            } · Auto-pause at ${budget?.thresholdUsd.toFixed(2)} · Resets 1st of month
          </div>
        </div>

        {/* Event log */}
        <div style={{
          background: '#fff', border: '1px solid oklch(92% 0.01 265)', borderRadius: 10,
          overflow: 'hidden',
        }}>
          <div style={{
            padding: '12px 16px', borderBottom: '1px solid oklch(92% 0.01 265)',
            fontSize: 14, fontWeight: 600, color: 'oklch(28% 0.06 265)',
          }}>
            Recent events ({events.length})
          </div>
          {events.length === 0 ? (
            <div style={{ padding: 24, textAlign: 'center', color: 'oklch(50% 0.03 265)', fontSize: 13 }}>
              No call events yet.
            </div>
          ) : (
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
              <thead style={{ background: 'oklch(98% 0.005 60)' }}>
                <tr style={{ textAlign: 'left', color: 'oklch(45% 0.04 265)', fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                  <th style={{ padding: '8px 12px' }}>When</th>
                  <th style={{ padding: '8px 12px' }}>Kind</th>
                  <th style={{ padding: '8px 12px' }}>Duration</th>
                  <th style={{ padding: '8px 12px' }}>Recording</th>
                  <th style={{ padding: '8px 12px' }}>Call SID</th>
                </tr>
              </thead>
              <tbody>
                {events.map((e) => (
                  <tr key={e.id} style={{ borderTop: '1px solid oklch(95% 0.01 265)' }}>
                    <td style={{ padding: '8px 12px', color: 'oklch(35% 0.04 265)', whiteSpace: 'nowrap' }}>
                      {new Date(e.created_at).toLocaleString()}
                    </td>
                    <td style={{ padding: '8px 12px', color: kindColor(e.kind), fontWeight: 600 }}>
                      {e.kind}
                    </td>
                    <td style={{ padding: '8px 12px', color: 'oklch(35% 0.04 265)' }}>
                      {e.duration_seconds != null ? `${e.duration_seconds}s` : '—'}
                    </td>
                    <td style={{ padding: '8px 12px' }}>
                      <RecordingCell event={e} />
                    </td>
                    <td style={{ padding: '8px 12px', color: 'oklch(50% 0.03 265)', fontFamily: 'ui-monospace, monospace', fontSize: 11 }}>
                      {e.call_sid || '—'}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    );
  }

  // One row of the Phone numbers table — owns its busy/error state so an
  // Approve/Revoke spinner doesn't block the rest of the list.
  function PhoneRow({ row, onChanged }) {
    const [busy, setBusy] = React.useState(false);
    const [err, setErr]   = React.useState('');
    const verified = Boolean(row.verifiedAt);
    const id = row.kind === 'instructor' ? row.instructorId : row.userId;
    const roleLabel = row.kind === 'instructor' ? 'Teacher' : 'Student';

    async function toggle() {
      setBusy(true); setErr('');
      try {
        await window.MaskedCalls.db.adminSetVerified(row.kind, id, !verified);
        await onChanged(); // re-fetch; this row stays mounted (stable key)
      } catch (e) {
        setErr(e.message || String(e));
      } finally {
        // Always clear — the row isn't unmounted on refresh, so without this
        // a successful approve would leave the button stuck on "…".
        setBusy(false);
      }
    }

    return (
      <tr style={{ borderTop: '1px solid oklch(95% 0.01 265)' }}>
        <td style={{ padding: '8px 12px', color: 'oklch(30% 0.04 265)' }}>
          <div style={{ fontWeight: 600 }}>{row.name || '(no name)'}</div>
          <div style={{ fontSize: 11, color: 'oklch(55% 0.03 265)' }}>{roleLabel}</div>
        </td>
        <td style={{ padding: '8px 12px', fontFamily: 'ui-monospace, monospace', color: row.phone ? 'oklch(30% 0.04 265)' : 'oklch(60% 0.02 265)' }}>
          {row.phone || '(unreadable)'}
        </td>
        <td style={{ padding: '8px 12px', whiteSpace: 'nowrap' }}>
          {verified ? (
            <span style={{ color: 'oklch(36% 0.13 145)', fontWeight: 600 }}>
              ✓ Verified
            </span>
          ) : (
            <span style={{ color: 'oklch(52% 0.16 70)', fontWeight: 600 }}>
              Not verified
            </span>
          )}
        </td>
        <td style={{ padding: '8px 12px', whiteSpace: 'nowrap' }}>
          <button type="button" onClick={toggle} disabled={busy}
            style={{
              padding: '5px 12px', borderRadius: 6, fontSize: 12, fontFamily: 'inherit',
              cursor: busy ? 'not-allowed' : 'pointer', fontWeight: 600,
              border: verified ? '1px solid oklch(86% 0.02 265)' : '1px solid transparent',
              background: verified ? '#fff' : 'oklch(45% 0.15 145)',
              color: verified ? 'oklch(45% 0.04 265)' : '#fff',
            }}>
            {busy ? '…' : verified ? 'Revoke' : 'Approve'}
          </button>
          {err && <div style={{ fontSize: 11, color: 'oklch(45% 0.18 25)', marginTop: 4, maxWidth: 220 }}>{err}</div>}
        </td>
      </tr>
    );
  }

  function kindColor(kind) {
    if (kind === 'inbound_bridged' || kind === 'outbound_completed') return 'oklch(36% 0.13 145)';
    if (kind.includes('failed') || kind === 'bridge_unrouted' || kind === 'budget_cap_hit') return 'oklch(40% 0.15 25)';
    return 'oklch(36% 0.06 265)';
  }

  // Lazy-loads a signed URL on click — we don't pre-sign every row's
  // recording up front because the page typically shows dozens of events
  // and most won't be played.
  function RecordingCell({ event }) {
    const [url, setUrl] = React.useState(null);
    const [busy, setBusy] = React.useState(false);
    const [err, setErr] = React.useState('');
    if (!event.recording_storage_path) {
      return <span style={{ color: 'oklch(60% 0.02 265)' }}>—</span>;
    }
    if (url) {
      return <audio controls src={url} style={{ height: 28, maxWidth: 240 }} />;
    }
    return (
      <button type="button"
        disabled={busy}
        onClick={async () => {
          setBusy(true); setErr('');
          try {
            const u = await window.MaskedCalls.db.getRecordingUrl(event.recording_storage_path);
            setUrl(u);
          } catch (e) { setErr(e.message || String(e)); }
          finally { setBusy(false); }
        }}
        style={{
          padding: '4px 10px', borderRadius: 4,
          border: '1px solid oklch(86% 0.02 265)', background: '#fff',
          cursor: busy ? 'not-allowed' : 'pointer',
          fontSize: 12, color: 'oklch(35% 0.04 265)',
          fontFamily: 'inherit',
        }}>
        {busy ? 'Loading…' : err || 'Play'}
      </button>
    );
  }

  window.AdminMaskedCallsTab = AdminMaskedCallsTab;
})();
