/* ===================================================================
   familiar.jsx — DM Familiar (window.DMFamiliar)

   A DM-private reasoning-assistant thread that lives in the right rail's
   "Familiar" tab (rendered only in DM view). The DM asks for help guiding
   the story or adjudicating a rule; the Worker (POST /familiar/ask) answers,
   grounded in the SRD 5.1 and the table's own house rules, and always leaves
   the final call to the DM.

   Nothing here touches the shared table chat — these messages are visible
   only to the DM, kept in component state for the session.

   No-build/global-scope rules: this loads before app.jsx, so it uses
   React.useState/useEffect/etc. (not destructured) to avoid redeclaring the
   shared React hook locals other files already pull in.
   =================================================================== */
const FAMILIAR_PROVIDERS = [
  { id: 'openai', label: 'OpenAI' },
  { id: 'anthropic', label: 'Anthropic' },
];
const famHouseKey = (room) => `embers:familiar:houserules:${room || 'default'}`;
const FAM_PROVIDER_KEY = 'embers:familiar:provider';

function DMFamiliar({ roomCode }) {
  const room = roomCode || 'default';
  const [thread, setThread] = React.useState([]);     // [{ role:'dm'|'familiar', text }]
  const [draft, setDraft] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');
  const [provider, setProvider] = React.useState('openai');
  const [houseRules, setHouseRules] = React.useState('');
  const [showRules, setShowRules] = React.useState(false);
  const endRef = React.useRef(null);

  // Load the persisted provider choice + this table's house rules.
  React.useEffect(() => {
    try { const p = localStorage.getItem(FAM_PROVIDER_KEY); if (p === 'openai' || p === 'anthropic') setProvider(p); } catch {}
  }, []);
  React.useEffect(() => {
    try { setHouseRules(localStorage.getItem(famHouseKey(room)) || ''); } catch {}
  }, [room]);

  React.useEffect(() => { endRef.current?.scrollIntoView?.({ block: 'end' }); }, [thread.length, busy]);

  const pickProvider = (p) => { setProvider(p); try { localStorage.setItem(FAM_PROVIDER_KEY, p); } catch {} };
  const editRules = (v) => { setHouseRules(v); try { localStorage.setItem(famHouseKey(room), v); } catch {} };

  const reasonText = (reason) => (
    reason === 'provider_unconfigured' ? 'This provider has no API key set on the server yet.' :
    reason === 'rate_limited' ? 'Slow down a moment — too many questions just now.' :
    reason === 'empty_question' ? 'Ask the Familiar something first.' :
    reason === 'network' ? 'Could not reach the server (it may be offline in local preview).' :
    'The Familiar could not answer just now. Please try again.'
  );

  const ask = React.useCallback(async () => {
    const q = draft.trim();
    if (!q || busy) return;
    if (!(window.Familiar && window.Familiar.ask)) { setError('Familiar client unavailable.'); return; }
    setError('');
    setBusy(true);
    const history = thread.slice();             // prior turns for context
    setThread(t => [...t, { role: 'dm', text: q }]);
    setDraft('');
    const res = await window.Familiar.ask({ question: q, history, houseRules, provider });
    if (res.ok) setThread(t => [...t, { role: 'familiar', text: res.reply }]);
    else setError(reasonText(res.reason));
    setBusy(false);
  }, [draft, busy, thread, houseRules, provider]);

  const onKey = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); ask(); } };

  return (
    <div className="familiar-panel">
      <div className="fam-head">
        <div className="fam-title"><span className="fam-glyph" aria-hidden="true">✦</span> DM Familiar</div>
        <label className="fam-provider">
          <span className="visually-hidden">Reasoning provider</span>
          <select value={provider} onChange={e => pickProvider(e.target.value)} aria-label="Reasoning provider">
            {FAMILIAR_PROVIDERS.map(p => <option key={p.id} value={p.id}>{p.label}</option>)}
          </select>
        </label>
        <button className="fam-rules-toggle" aria-expanded={showRules} onClick={() => setShowRules(s => !s)}>
          House rules
        </button>
      </div>

      {showRules && (
        <div className="fam-rules">
          <label className="fam-rules-lab" htmlFor="fam-house-rules">House rules (these override standard 5e for this table)</label>
          <textarea id="fam-house-rules" className="fam-rules-input" rows={4}
            placeholder="e.g. Critical hits deal max damage + a roll. Potions are a bonus action. No flanking."
            value={houseRules} onChange={e => editRules(e.target.value)} />
        </div>
      )}

      <div className="fam-scroll" role="log" aria-live="polite" aria-label="DM Familiar conversation">
        {thread.length === 0 && !busy && (
          <p className="fam-hint">Ask for a ruling, a plot nudge, an NPC on the spot, or an encounter idea.
            The Familiar advises — every final call stays yours.</p>
        )}
        {thread.map((m, i) => (
          <div key={i} className={`fam-msg ${m.role}`}>
            <span className="fam-who">{m.role === 'dm' ? 'You' : 'Familiar'}</span>
            <span className="fam-text">{m.text}</span>
          </div>
        ))}
        {busy && <div className="fam-msg familiar busy"><span className="fam-who">Familiar</span><span className="fam-text">…thinking</span></div>}
        {error && <div className="fam-error" role="alert">{error}</div>}
        <div ref={endRef} />
      </div>

      <div className="fam-input">
        <textarea value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={onKey} rows={2}
          placeholder="Ask the Familiar… (Enter to send, Shift+Enter for a new line)"
          aria-label="Ask the DM Familiar" disabled={busy} />
        <button className="btn" onClick={ask} disabled={busy || !draft.trim()}>Ask</button>
      </div>
    </div>
  );
}
window.DMFamiliar = DMFamiliar;
