// Raccoon.jsx — "Rocky" the raccoon study buddy: a full chat page + a floating cheer mascot.

// Gather study materials FRIENDS have shared, as context Rocky can draw on.
function rockyFriendKnowledge() {
  const out = [];
  (window.FRIENDS || []).forEach((f) => {
    if (!f.shared) return;
    (f.domains || []).forEach((d) => (d.topics || []).forEach((t) => {
      if (!t.summary && !t.note) return;
      out.push({
        friend: f.name.split(' ')[0], domain: d.name, topic: t.name,
        head: t.summary ? t.summary.head : '',
        core: t.summary && t.summary.secs && t.summary.secs[0] ? t.summary.secs[0].b : t.note || '',
        concepts: (t.concepts || []).map((c) => c.label)
      });
    }));
  });
  return out;
}
// The learner's own generated summaries, as context too.
function rockyOwnKnowledge() {
  const out = [];
  (window.TOPICS || []).forEach((t) => {
    const sm = (window.MATERIALS || []).find((m) => m.topic === t.id && m.type === 'summary');
    const s = sm && (window.SUMMARIES || {})[sm.id];
    if (s) out.push({ topic: t.name, head: s.head, intro: s.intro });
  });
  return out;
}
// Build a bounded, question-relevant knowledge block for the prompt.
function rockyContext(q) {
  const kw = (q || '').toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 3);
  const score = (hay) => {const h = hay.toLowerCase();let s = 0;kw.forEach((w) => {if (h.includes(w)) s++;});return s;};
  const fk = rockyFriendKnowledge();
  const ranked = fk.map((e) => ({ e, s: score(e.topic + ' ' + e.domain + ' ' + e.concepts.join(' ') + ' ' + e.head + ' ' + e.core) })).
  sort((a, b) => b.s - a.s);
  const top = ranked.filter((x) => x.s > 0).slice(0, 6).map((x) => x.e);
  const detail = top.map((e) => `• [${e.friend}'s ${e.domain} notes] ${e.topic}${e.head ? ' — ' + e.head : ''}. ${String(e.core).slice(0, 320)}${e.concepts.length ? ' Key concepts: ' + e.concepts.join(', ') + '.' : ''}`).join('\n');
  const ownTop = rockyOwnKnowledge().map((e) => ({ e, s: score(e.topic + ' ' + e.head + ' ' + e.intro) })).
  filter((x) => x.s > 0).sort((a, b) => b.s - a.s).slice(0, 4).
  map((x) => `• [your notes] ${x.e.topic} — ${x.e.head}. ${String(x.e.intro).slice(0, 240)}`).join('\n');
  const index = fk.map((e) => `${e.friend}: ${e.topic} (${e.domain})`).join('; ');
  return { detail, ownTop, index, hasMatch: top.length > 0 || !!ownTop };
}

function RockyChat() {
  const [msgs, setMsgs] = React.useState([
  { role: 'rocky', text: 'Hi, I’m Rocky! Ask me anything about your materials — and I can also pull from study materials your friends have shared with you.' }]
  );
  const [input, setInput] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  // Voice dictation — the learner can speak their question instead of typing it.
  const [listening, setListening] = React.useState(false);
  const [micOk, setMicOk] = React.useState(true);
  const recRef = React.useRef(null);
  const baseRef = React.useRef(''); // text already in the box when dictation started
  React.useEffect(() => () => {try {recRef.current && recRef.current.stop();} catch (e) {}}, []);
  const toggleMic = () => {
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SR) {setMicOk(false);return;}
    if (listening) {try {recRef.current && recRef.current.stop();} catch (e) {}return;}
    try {
      const rec = new SR();
      rec.continuous = true;rec.interimResults = true;rec.lang = 'en-US';
      baseRef.current = input.trim() ? input.trim() + ' ' : '';
      rec.onstart = () => {setListening(true);setMicOk(true);};
      rec.onresult = (e) => {
        let finalTxt = '', interim = '';
        for (let i = 0; i < e.results.length; i++) {
          const r = e.results[i];
          if (r.isFinal) finalTxt += r[0].transcript; else interim += r[0].transcript;
        }
        // Voice command: saying “send” at the end of a finished sentence submits it.
        const finalCombined = (baseRef.current + finalTxt).replace(/\s+/g, ' ').trim();
        const cmd = finalCombined.match(/^(.*?)[\s,]*\bsend(?:\s+(?:it|this|message|now|please))?[\s.!?]*$/i);
        if (cmd && cmd[1].trim() && !rec._sent) {
          rec._sent = true;
          const cleaned = cmd[1].trim();
          setInput(cleaned);
          try {rec.stop();} catch (_) {}
          ask(cleaned);
          return;
        }
        const combined = (baseRef.current + finalTxt + interim).replace(/\s+/g, ' ').replace(/^\s+/, '');
        setInput(combined);
      };
      rec.onerror = (e) => {if (e.error === 'not-allowed' || e.error === 'service-not-allowed') setMicOk(false);setListening(false);};
      rec.onend = () => {setListening(false);recRef.current = null;};
      recRef.current = rec;
      rec.start();
    } catch (e) {setListening(false);}
  };
  const bodyRef = React.useRef(null);
  React.useEffect(() => {const el = bodyRef.current;if (el) el.scrollTop = el.scrollHeight;}, [msgs, busy]);

  const GREETING = { role: 'rocky', text: 'Hi, I’m Rocky! Ask me anything about your materials — and I can also pull from study materials your friends have shared with you.' };
  const [saved, setSaved] = React.useState(() => {
    try {return JSON.parse(localStorage.getItem('pl-rocky-chats') || '[]');} catch (e) {return [];}
  });
  const persist = (list) => {setSaved(list);try {localStorage.setItem('pl-rocky-chats', JSON.stringify(list));} catch (e) {}};
  const hasConvo = msgs.some((m) => m.role === 'user');

  // Remember which suggestion topics the learner has already tried, so the chips
  // rotate to fresh ones after a chip is clicked or a chat is saved.
  const [usedSug, setUsedSug] = React.useState(() => {
    try {return JSON.parse(localStorage.getItem('pl-rocky-used') || '[]');} catch (e) {return [];}
  });
  const markUsed = (topic) => {
    setUsedSug((prev) => {
      if (prev.includes(topic)) return prev;
      const next = [...prev, topic];
      try {localStorage.setItem('pl-rocky-used', JSON.stringify(next));} catch (e) {}
      return next;
    });
  };

  const finish = async () => {
    if (!hasConvo || busy) return;
    setBusy(true);
    const firstQ = (msgs.find((m) => m.role === 'user') || {}).text || 'Chat with Rocky';
    let title = '';
    try {
      if (window.claude && window.claude.complete) {
        const convo = msgs.map((m) => (m.role === 'user' ? 'Learner: ' : 'Rocky: ') + m.text).join('\n');
        const r = await window.claude.complete(`Summarize this study chat as a short, specific title (4–7 words, no quotes, no trailing period):\n\n${convo}\n\nTitle:`);
        title = (r || '').trim().replace(/^["'\s]+|["'\s.]+$/g, '');
      }
    } catch (e) {}
    if (!title) title = firstQ.length > 48 ? firstQ.slice(0, 48) + '…' : firstQ;
    const entry = { id: 'c' + Date.now(), title, msgs: msgs.slice(), questions: msgs.filter((m) => m.role === 'user').length };
    persist([entry, ...saved]);
    setMsgs([GREETING]);
    setBusy(false);
  };
  const reopen = (entry) => {setMsgs(entry.msgs.slice());};
  const remove = (id) => persist(saved.filter((s) => s.id !== id));

  const ask = async (override) => {
    const q = (override != null ? override : input).trim();
    if (!q || busy) return;
    try {recRef.current && recRef.current.stop();} catch (e) {}
    setMsgs((m) => [...m, { role: 'user', text: q }]);
    setInput('');setBusy(true);
    let answer = '?';
    try {
      if (window.claude && window.claude.complete) {
        const ctx = rockyContext(q);
        const knowledge = [
        ctx.ownTop ? 'FROM THE LEARNER’S OWN MATERIALS:\n' + ctx.ownTop : '',
        ctx.detail ? 'FROM FRIENDS’ SHARED MATERIALS (most relevant):\n' + ctx.detail : '',
        'ALL SHARED TOPICS AVAILABLE (friend: topic): ' + ctx.index].
        filter(Boolean).join('\n\n');
        const prompt = `You are Rocky, a warm, encouraging raccoon study buddy inside a learning app called Pathline. You can draw on the learner’s OWN study materials AND on materials their FRIENDS have shared with them. The learner’s friends have shared full reading paths on subjects like Geology, Electrical Engineering, Computer Science, Civil Engineering, Architecture, the Human Body, Astronomy, and Botany — so you can help with far more than the learner’s own topics.\n\nUse the knowledge below when it is relevant. When you draw on a friend’s shared material, mention whose notes it came from (e.g. “Priya’s Architecture notes cover this”). If the friends’ materials are relevant to a practical goal (like building something), connect the learner to the right friend’s notes rather than refusing. Answer helpfully and concisely (2–4 short sentences, no markdown headers). Only if you truly have nothing relevant in your own knowledge or the materials below, reply with exactly the single character "?" and nothing else.\n\n${knowledge}\n\nLearner: ${q}\nRocky:`;
        const r = await window.claude.complete(prompt);
        answer = (r || '').trim().replace(/\*\*(.+?)\*\*/g, '$1').replace(/^#+\s*/gm, '') || '?';
      }
    } catch (e) {answer = '?';}
    setMsgs((m) => [...m, { role: 'rocky', text: answer }]);
    setBusy(false);
  };

  return (
    <React.Fragment>
    <div className="rocky-chat">
      <div className="rac-body" ref={bodyRef}>
        {msgs.map((m, i) =>
          <div key={i} className={'rac-msg ' + m.role}>
            {m.role === 'rocky' && <span className="rac-msg-ava"><Icon name="diamond" size={14} /></span>}
            <div className="rac-bubble">{m.text}</div>
          </div>
          )}
        {busy && <div className="rac-msg rocky"><span className="rac-msg-ava"><Icon name="diamond" size={14} /></span><div className="rac-bubble rac-typing"><span></span><span></span><span></span></div></div>}
      </div>
      {!hasConvo && (() => {
          const fk = rockyFriendKnowledge();
          const used = new Set(usedSug);
          // Topics the learner hasn't tried yet take priority; fall back to all once exhausted.
          const fresh = fk.filter((e) => !used.has(e.topic));
          const pool = fresh.length ? fresh : fk;
          // One per friend for variety, rotating offset so repeats differ.
          const byFriend = {};
          pool.forEach((e) => {(byFriend[e.friend] = byFriend[e.friend] || []).push(e);});
          const friends = Object.keys(byFriend);
          const offset = usedSug.length + saved.length; // shifts after each click or saved chat
          const picks = [];
          for (const f of friends) {
            const list = byFriend[f];
            picks.push(list[offset % list.length]);
            if (picks.length >= 3) break;
          }
          if (!picks.length) return null;
          const allTried = fresh.length === 0;
          return (
            <div className="rac-suggest">
            <span className="rac-suggest-lab"><Icon name="sparkles" size={13} /> {allTried ? 'More to explore from friends’ materials:' : 'Try asking, using a friend’s materials:'}</span>
            <div className="rac-suggest-row">
              {picks.map((e, i) =>
                <button key={i} className="chip" onClick={() => {setInput('What do ' + e.friend + '’s notes say about ' + e.topic + '?');markUsed(e.topic);}}>
                  {e.topic} <span style={{ color: 'var(--ink-4)' }}>· {e.friend}</span>
                </button>)}
            </div>
          </div>);
        })()}
      <div className="rac-input">
        <input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => {if (e.key === 'Enter') ask();}}
          placeholder={listening ? 'Listening… speak, then say “send” to send' : 'Ask Rocky anything — yours or a friend’s materials…'} />
        <button className={'btn sm mic-btn' + (listening ? ' rec' : '')} onClick={toggleMic} disabled={busy}
          aria-pressed={listening} title={!micOk ? 'Voice input unavailable in this browser' : listening ? 'Stop dictation' : 'Ask by voice'}>
          <Icon name="mic" size={16} />
        </button>
        <button className="btn primary sm" onClick={() => ask()} disabled={busy || !input.trim()}><Icon name="arrow-up-right" size={16} /></button>
      </div>
      {listening && <div className="rac-dictate"><span className="rac-dictate-dot" /> Listening… speak your question, then say <strong style={{ color: 'var(--blue-ink)' }}>“send”</strong> to send it — or tap the send button.</div>}
      {!micOk && <div className="rac-dictate err">Voice input isn’t available in this browser — you can type your question instead.</div>}
      <div className="rac-foot">
        <span className="t-small">{hasConvo ? 'Save this chat to revisit Rocky’s answers later.' : 'Saved chats appear below — ask something to start.'}</span>
        <button className="btn sm" onClick={finish} disabled={busy || !hasConvo} title={hasConvo ? 'Save this chat' : 'Ask a question first'}><Icon name="check" size={15} /> Finish & save chat</button>
      </div>
      </div>
      {saved.length > 0 &&
      <div style={{ marginTop: 24, paddingTop: 22, borderTop: '1px solid var(--line)' }}>
          <h2 style={{ fontSize: 14, display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
            <Icon name="message" size={16} style={{ color: 'var(--ink-3)' }} /> Saved chats <span className="count-pill">{saved.length}</span>
          </h2>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {saved.map((s) =>
          <div key={s.id} className="card" style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 16px' }}>
                <span style={{ width: 34, height: 34, borderRadius: 9, flex: 'none', display: 'grid', placeItems: 'center', background: 'var(--surface-2)', color: 'var(--ink-3)' }}><Icon name="message" size={16} /></span>
                <button className="lrow" onClick={() => reopen(s)} style={{ flex: 1, textAlign: 'left', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>{s.title}</div>
                  <div className="t-small">{s.questions} {s.questions === 1 ? 'question' : 'questions'} · reopen to continue</div>
                </button>
                <button className="btn ghost sm" onClick={() => remove(s.id)} title="Delete chat"><Icon name="trash" size={15} /></button>
              </div>
          )}
          </div>
        </div>}
    </React.Fragment>);

}
window.RockyChat = RockyChat;

// Full page reached from the leaf icon in the nav.
function RockyPage({ toast }) {
  const [say, setSay] = React.useState(false);
  React.useEffect(() => {if (!say) return;const t = setTimeout(() => setSay(false), 3200);return () => clearTimeout(t);}, [say]);
  return (
    <div className="content-pad fade-up">
      <div className="page-head rocky-head" style={{ marginBottom: 18 }}>
        <div className="rocky-head-text">
          <p className="eyebrow">Study buddy</p>
          <h1>Ask Rocky</h1>
          <p className="sub">Your raccoon study buddy — ask anything about your materials, or your friends’ shared ones.</p>
        </div>
        <div className="rocky-hero" style={{ position: 'relative', flex: 'none', alignSelf: 'flex-start' }}>
          {say &&
          <div className="fade-up" style={{ position: 'absolute', right: 'calc(100% - 26px)', top: 18, zIndex: 4, width: 'max-content', maxWidth: 260,
            background: 'var(--paper)', border: '1px solid var(--line-strong)', borderRadius: 16, borderBottomRightRadius: 4,
            padding: '11px 14px', fontSize: 14, fontWeight: 500, color: 'var(--ink)', lineHeight: 1.4, boxShadow: 'var(--shadow-md)' }}>
              Craft craft! New ore for me to fudge with~
            </div>
          }
          <img src={window.__resources && window.__resources.raccoon || 'app/raccoon.png'} alt="Rocky" onClick={() => setSay(true)} role="button" tabIndex={0}
          onKeyDown={(e) => {if (e.key === 'Enter' || e.key === ' ') {e.preventDefault();setSay(true);}}}
          title="Pet Rocky"
          style={{ objectFit: 'contain', display: 'block', margin: '-34px 36px -80px 0', position: 'relative', zIndex: 2, cursor: 'pointer', transition: 'transform .18s', filter: 'drop-shadow(0 6px 14px rgba(0,0,0,.18))', height: "200px", width: "200px" }}
          onMouseEnter={(e) => {e.currentTarget.style.transform = 'scale(1.04) rotate(-2deg)';}}
          onMouseLeave={(e) => {e.currentTarget.style.transform = 'none';}} />
        </div>
      </div>
      <div className="card pad" style={{ display: 'flex', gap: 14, alignItems: 'center', marginBottom: 16 }}>
        <span role="img" aria-label="Rocky" style={{ width: 64, height: 64, borderRadius: '50%', flex: 'none', border: '1px solid var(--line)', backgroundColor: 'var(--surface-2)', backgroundImage: 'url(' + (window.__resources && window.__resources.raccoon || 'app/raccoon.png') + ')', backgroundSize: '188%', backgroundPosition: '50% 28%', backgroundRepeat: 'no-repeat', boxShadow: 'var(--shadow-sm)' }} />
        <div>
          <div style={{ fontWeight: 600, fontSize: 16 }}>Rocky</div>
          <div className="t-small">Ask about your topics, summaries, or decks — I can also pull from your friends’ shared materials. If I’m not sure, I’ll just say “?”.</div>
        </div>
      </div>
      <RockyChat />
    </div>);

}
window.RockyPage = RockyPage;

// Floating cheer mascot — celebrates progress and jumps to Rocky's page on click.
function Raccoon({ go }) {
  const [cheer, setCheer] = React.useState(false);
  React.useEffect(() => {
    const onStep = () => {setCheer(true);window.clearTimeout(onStep._t);onStep._t = window.setTimeout(() => setCheer(false), 2800);};
    window.addEventListener('pl-step', onStep);
    return () => window.removeEventListener('pl-step', onStep);
  }, []);
  return (
    <button className="rac-launch" onClick={() => go('rocky')} title="Ask Rocky" aria-label="Ask Rocky the raccoon">
      <img src={window.__resources && window.__resources.raccoon || 'app/raccoon.png'} alt="Rocky the raccoon" />
      {cheer && <span className="rac-cheer">hummm nice</span>}
    </button>);

}
window.Raccoon = Raccoon;