// dashboard2.jsx — Admin Dashboard. No client-side PIN: entries are fetched
// from /api/admin/entries with a bearer token held in sessionStorage only.
const { useState: useDState, useEffect: useDEffect, useRef: useDRef } = React;

const ADMIN_TOKEN_KEY = 'bol:admin-token';

async function fetchEntries(token) {
  const res = await fetch('/api/admin/entries', {
    headers: { Authorization: 'Bearer ' + token },
    cache: 'no-store',
  });
  if (res.status === 401) { const e = new Error('That token was not accepted.'); e.unauthorized = true; throw e; }
  if (!res.ok) {
    let msg = 'The server could not return the entries.';
    try { const d = await res.json(); if (d && d.message) msg = d.message; } catch (err) { /* keep default */ }
    throw new Error(msg);
  }
  const data = await res.json();
  return (data && data.entries) || [];
}

function StatCard({ icon, value, label }) {
  return (
    <Card style={{ flex: 1, minWidth: 0, padding: '16px 18px', display: 'flex', alignItems: 'center', gap: 14, boxShadow: T.shadow.soft }}>
      <div style={{ fontSize: 30, lineHeight: 1 }}>{icon}</div>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 30, color: T.color.text, lineHeight: 1 }}>{value}</div>
        <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.textSoft, marginTop: 3 }}>{label}</div>
      </div>
    </Card>
  );
}

function FilterChip({ children, active, onClick }) {
  return (
    <button onClick={onClick} style={{
      fontFamily: T.font.head, fontWeight: 700, fontSize: 13, cursor: 'pointer', padding: '7px 13px',
      borderRadius: 100, border: '1.5px solid ' + (active ? T.color.amber : T.color.border),
      background: active ? T.color.amber : '#FFFDFA', color: active ? '#fff' : T.color.textSoft, transition: 'all .14s', whiteSpace: 'nowrap',
    }}>{children}</button>
  );
}

function TokenGate({ onPass, onExit }) {
  const [token, setToken] = useDState('');
  const [err, setErr] = useDState('');
  const [busy, setBusy] = useDState(false);
  const ref = useDRef(null);
  useDEffect(() => { const t = setTimeout(() => ref.current && ref.current.focus(), 200); return () => clearTimeout(t); }, []);

  const submit = async () => {
    const value = token.trim();
    if (!value || busy) return;
    setBusy(true); setErr('');
    try {
      const entries = await fetchEntries(value);
      try { sessionStorage.setItem(ADMIN_TOKEN_KEY, value); } catch (e) { /* session-only */ }
      onPass(value, entries);
    } catch (e) {
      setErr(e && e.message ? e.message : 'Could not reach the server.');
      setToken('');
      setBusy(false);
    }
  };

  return (
    <div style={{ maxWidth: 380, margin: '6vh auto 0' }}>
      <Card style={{ padding: 34, textAlign: 'center' }}>
        <div style={{ fontSize: 42 }}>🔐</div>
        <h2 style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 22, margin: '12px 0 4px' }}>Dashboard Access</h2>
        <p style={{ fontFamily: T.font.body, fontSize: 14, color: T.color.textSoft, margin: '0 0 20px' }}>Enter your admin token to continue.</p>
        <input ref={ref} type="password" value={token} aria-label="Admin token" autoComplete="off" spellCheck="false"
          onChange={(e) => { setErr(''); setToken(e.target.value.slice(0, 200)); }}
          onKeyDown={(e) => e.key === 'Enter' && submit()}
          className="bol-input"
          style={{
            width: '100%', boxSizing: 'border-box', textAlign: 'center', fontFamily: T.font.head, fontWeight: 700,
            fontSize: 18, letterSpacing: 4, color: T.color.text, background: '#FFFDFA',
            border: '1.5px solid ' + (err ? T.color.danger : T.color.border), borderRadius: T.radius.input,
            padding: '14px 10px', outline: 'none', transition: 'border-color .18s',
          }} placeholder="••••••••" />
        {err && <div style={{ fontFamily: T.font.body, fontSize: 13, color: T.color.danger, marginTop: 10 }}>{err}</div>}
        <div style={{ display: 'flex', gap: 10, marginTop: 20 }}>
          <Btn variant="ghost" onClick={onExit}>← Reader View</Btn>
          <Btn full disabled={busy} onClick={submit}>{busy ? 'Checking…' : 'Unlock'}</Btn>
        </div>
      </Card>
    </div>
  );
}

function EntryCard({ e }) {
  const stars = '★★★★★☆☆☆☆☆'.slice(5 - (e.rating || 0), 10 - (e.rating || 0));
  const answered = PROMPTS.filter((p) => (e.prompts || {})[p.key] && e.prompts[p.key].trim());
  const attachments = e.attachments || [];
  return (
    <Card style={{ padding: 20, boxShadow: T.shadow.soft }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {e.code && <Badge tone="amber">{e.code}</Badge>}
          {e.role && <Badge tone="sage">{e.role}</Badge>}
        </div>
        <div style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, whiteSpace: 'nowrap' }}>{fmtDate(e.timestamp)}</div>
      </div>

      {e.name && <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 16, color: T.color.text, marginTop: 12 }}>{e.name}</div>}
      {e.rating > 0 && <div style={{ fontSize: 17, color: T.color.amber, letterSpacing: 2, marginTop: e.name ? 4 : 12 }}>{stars}</div>}

      {answered.map((p) => (
        <div key={p.key} style={{ marginTop: 14 }}>
          <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 10.5, letterSpacing: 0.8, textTransform: 'uppercase', color: T.color.amber, marginBottom: 4 }}>{p.label}</div>
          <div style={{ fontFamily: T.font.body, fontSize: 14.5, lineHeight: 1.55, color: T.color.text }}>{e.prompts[p.key]}</div>
        </div>
      ))}

      {e.comments && (
        <div style={{ marginTop: 14 }}>
          <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 10.5, letterSpacing: 0.8, textTransform: 'uppercase', color: T.color.textFaint, marginBottom: 4 }}>General comments</div>
          <div style={{ fontFamily: T.font.body, fontSize: 14.5, lineHeight: 1.55, color: T.color.text }}>{e.comments}</div>
        </div>
      )}

      {e.email && <div style={{ fontFamily: T.font.body, fontSize: 13, color: T.color.link, marginTop: 14 }}>{e.email}</div>}

      {attachments.length > 0 && (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 14 }}>
          {attachments.map((f, i) => (
            <span key={i} style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, border: '1px solid ' + T.color.border, borderRadius: 100, padding: '4px 10px' }}>
              📎 {f.name}
            </span>
          ))}
        </div>
      )}
    </Card>
  );
}

function AdminDashboard({ onExit }) {
  const [token, setToken] = useDState(() => { try { return sessionStorage.getItem(ADMIN_TOKEN_KEY) || ''; } catch (e) { return ''; } });
  const [entries, setEntries] = useDState([]);
  const [status, setStatus] = useDState('idle'); // idle | loading | ready | error
  const [loadError, setLoadError] = useDState('');
  const [ratingF, setRatingF] = useDState('all');
  const [roleF, setRoleF] = useDState('all');
  const [baseUrl, setBaseUrl] = useDState('https://thebookoflightseries.com');
  const [accessCode, setAccessCode] = useDState('');
  const [copied, setCopied] = useDState(false);

  const signOut = () => {
    try { sessionStorage.removeItem(ADMIN_TOKEN_KEY); } catch (e) { /* ignore */ }
    setToken(''); setEntries([]); setStatus('idle'); setLoadError('');
  };

  const load = async (value) => {
    setStatus('loading'); setLoadError('');
    try {
      setEntries(await fetchEntries(value));
      setStatus('ready');
    } catch (e) {
      if (e && e.unauthorized) { signOut(); return; }
      setLoadError(e && e.message ? e.message : 'Could not reach the server.');
      setStatus('error');
    }
  };

  useDEffect(() => { if (token && status === 'idle') load(token); }, [token]);

  if (!token) {
    return <TokenGate onExit={onExit} onPass={(value, list) => { setToken(value); setEntries(list); setStatus('ready'); }} />;
  }

  const filtered = entries.filter((e) =>
    (ratingF === 'all' || e.rating === Number(ratingF)) &&
    (roleF === 'all' || e.role === roleF));

  const rated = entries.filter((e) => e.rating > 0);
  const avg = rated.length ? (rated.reduce((s, e) => s + e.rating, 0) / rated.length).toFixed(1) : '—';

  const link = baseUrl && accessCode ? baseUrl.replace(/\/$/, '') + '?code=' + encodeURIComponent(accessCode.trim()) : '';

  const exportJson = () => {
    const blob = new Blob([JSON.stringify(entries, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = 'book-of-light-feedback.json'; a.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  };

  const copyLink = async () => {
    try { await navigator.clipboard.writeText(link); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch (e) {}
  };

  const inputStyle = {
    width: '100%', boxSizing: 'border-box', fontFamily: T.font.body, fontSize: 14.5, color: T.color.text,
    background: '#FFFDFA', border: '1.5px solid ' + T.color.border, borderRadius: T.radius.input, padding: '10px 12px', outline: 'none',
  };

  return (
    <div style={{ maxWidth: T.maxDash, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* header */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 12, flexWrap: 'wrap' }}>
        <div>
          <h1 style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 26, margin: 0, color: T.color.text }}>📖 Feedback Dashboard</h1>
          <div style={{ fontFamily: T.font.body, fontSize: 14, color: T.color.textSoft, marginTop: 3 }}>The Book of Light — Early Reader Reviews</div>
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          <Btn variant="ghost" onClick={signOut}>Sign out</Btn>
          <Btn variant="ghost" onClick={onExit}>← Reader View</Btn>
        </div>
      </div>

      {status === 'error' && (
        <Card style={{ padding: 20, boxShadow: T.shadow.soft, borderColor: T.color.danger }}>
          <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 15, color: T.color.danger }}>{loadError}</div>
          <div style={{ fontFamily: T.font.body, fontSize: 13.5, color: T.color.textSoft, margin: '6px 0 14px' }}>
            Nothing has been lost — entries live in the database, not in this browser.
          </div>
          <Btn variant="ghost" onClick={() => load(token)}>Try again</Btn>
        </Card>
      )}

      {/* stats */}
      <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}>
        <StatCard icon="📝" value={status === 'loading' ? '…' : entries.length} label="Total submissions" />
        <StatCard icon="⭐" value={status === 'loading' ? '…' : avg} label="Average rating" />
      </div>

      {/* modules strip */}
      <Card style={{ padding: 16, boxShadow: T.shadow.soft }}>
        <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 12, letterSpacing: 0.6, textTransform: 'uppercase', color: T.color.textFaint, marginBottom: 10 }}>Portal modules</div>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {MODULES.map((m) => (
            <div key={m.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 11px', borderRadius: 100, fontFamily: T.font.head, fontWeight: 700, fontSize: 12.5,
              background: m.status === 'live' ? T.color.sageLight : '#F3EEE6', color: m.status === 'live' ? T.color.sageDeep : T.color.textFaint, border: '1px solid ' + (m.status === 'live' ? 'transparent' : T.color.border) }}>
              <span>{m.icon}</span>{m.short}
              <span style={{ fontSize: 9.5, opacity: 0.85, textTransform: 'uppercase', letterSpacing: 0.5 }}>{m.status === 'live' ? '● live' : 'soon'}</span>
            </div>
          ))}
        </div>
      </Card>

      {/* filters + export */}
      <Card style={{ padding: 16, boxShadow: T.shadow.soft }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, flexWrap: 'wrap', marginBottom: 12 }}>
          <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 14, color: T.color.text }}>Filters</div>
          <Btn variant="secondary" style={{ fontSize: 14, padding: '9px 16px' }} onClick={exportJson}>📥 Export JSON</Btn>
        </div>
        <div style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, marginBottom: 6 }}>By rating</div>
        <div style={{ display: 'flex', gap: 7, flexWrap: 'wrap', marginBottom: 12 }}>
          <FilterChip active={ratingF === 'all'} onClick={() => setRatingF('all')}>All</FilterChip>
          {[5, 4, 3, 2, 1].map((n) => <FilterChip key={n} active={ratingF === String(n)} onClick={() => setRatingF(String(n))}>{n} ★</FilterChip>)}
        </div>
        <div style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, marginBottom: 6 }}>By role</div>
        <div style={{ display: 'flex', gap: 7, flexWrap: 'wrap' }}>
          <FilterChip active={roleF === 'all'} onClick={() => setRoleF('all')}>All</FilterChip>
          {ROLES.map((r) => <FilterChip key={r} active={roleF === r} onClick={() => setRoleF(r)}>{r}</FilterChip>)}
        </div>
      </Card>

      {/* QR & link generator */}
      <Card style={{ padding: 16, boxShadow: T.shadow.soft }}>
        <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 14, color: T.color.text, marginBottom: 12 }}>🔗 QR & link generator</div>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 12 }}>
          <div style={{ flex: 1, minWidth: 180 }}>
            <div style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, marginBottom: 4 }}>Base URL</div>
            <input style={inputStyle} value={baseUrl} onChange={(e) => setBaseUrl(e.target.value)} placeholder="https://thebookoflightseries.com" />
          </div>
          <div style={{ flex: 1, minWidth: 180 }}>
            <div style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint, marginBottom: 4 }}>Access code</div>
            <input style={{ ...inputStyle, letterSpacing: 1 }} value={accessCode} onChange={(e) => setAccessCode(e.target.value.toUpperCase())} placeholder="READER-0042" />
          </div>
        </div>
        {link ? (
          <div>
            <div style={{ fontFamily: T.font.body, fontSize: 13.5, color: T.color.link, wordBreak: 'break-all', background: '#F7FAFC', border: '1px solid ' + T.color.border, borderRadius: 10, padding: '10px 12px' }}>{link}</div>
            <div style={{ display: 'flex', gap: 10, marginTop: 10 }}>
              <Btn variant="ghost" onClick={copyLink}>{copied ? '✓ Copied' : '📋 Copy Link'}</Btn>
              <Btn variant="secondary" onClick={() => window.open('https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=' + encodeURIComponent(link), '_blank')}>📱 View QR Code</Btn>
            </div>
          </div>
        ) : (
          <div style={{ fontFamily: T.font.body, fontSize: 13, color: T.color.textFaint }}>Fill both fields to generate a link and QR code.</div>
        )}
      </Card>

      {/* entries */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginTop: 4 }}>
        <h2 style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 18, margin: 0, color: T.color.text }}>Feedback entries</h2>
        <span style={{ fontFamily: T.font.body, fontSize: 13, color: T.color.textFaint }}>{filtered.length} shown</span>
      </div>

      {filtered.length === 0 ? (
        <Card style={{ padding: 44, textAlign: 'center', boxShadow: T.shadow.soft }}>
          <div style={{ fontSize: 44 }}>{status === 'loading' ? '⏳' : '📭'}</div>
          <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 16, color: T.color.textSoft, marginTop: 10 }}>
            {status === 'loading' ? 'Loading entries…'
              : status === 'error' ? 'Entries could not be loaded.'
              : entries.length === 0 ? 'No feedback yet — share those QR codes!'
              : 'No entries match these filters.'}
          </div>
        </Card>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {filtered.map((e) => <EntryCard key={e.id} e={e} />)}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { AdminDashboard });
