// Mastery.jsx — per-topic mastery model.
//
// Mastery is earned, not given. Studying actions each add a fixed amount, but
// the bar is gated in two places that mirror real mastery:
//   • You can only COMPLETE 80% once you've uploaded at least 5 files to the
//     topic (the study actions + 5 files sum to exactly 80%).
//   • The final 20% → 100% unlocks only when you PUBLISH your own original
//     material that other learners can save as a reference.
//
// State lives in localStorage so it survives reloads; changes broadcast a
// 'pl-mastery' event so every view (header stat, panel) recomputes live.

const MASTERY_STEPS = [
{ key: 'deck', label: 'Complete a flashcard challenge', hint: 'Finish a deck end-to-end', weight: 20, icon: 'cards' },
{ key: 'summary', label: 'Review & listen to a summary', hint: 'Open a summary and play it back', weight: 15, icon: 'headphones' },
{ key: 'shared', label: 'Share materials with a friend', hint: 'Send a concept map or deck to someone', weight: 15, icon: 'users' },
{ key: 'files', label: 'Upload 5 files to this topic', hint: 'Your sources build the foundation', weight: 30, icon: 'book' },
{ key: 'published', label: 'Publish your own original material', hint: 'Make work others can save as reference', weight: 20, icon: 'sparkles', gated: true }];


function getMastery(topicId) { try { return JSON.parse(localStorage.getItem('pl-mastery-' + topicId) || '{}') || {}; } catch (e) { return {}; } }
function topicFileCount(topicId) { try { return (JSON.parse(localStorage.getItem('pl-topic-files-' + topicId) || '[]') || []).length; } catch (e) { return 0; } }
function setMasteryFlag(topicId, key, val) {
  if (!topicId) return;
  const m = getMastery(topicId);
  const v = val === undefined ? true : val;
  if (m[key] === v) return;
  m[key] = v;
  try { localStorage.setItem('pl-mastery-' + topicId, JSON.stringify(m)); } catch (e) {}
  try { window.dispatchEvent(new CustomEvent('pl-mastery', { detail: { topicId, key } })); } catch (e) {}
}

// Compute the live mastery percentage + a per-step breakdown for a topic.
function computeMastery(topicId) {
  const m = getMastery(topicId);
  const files = topicFileCount(topicId);
  const filesDone = Math.min(files, 5);
  const base = (m.deck ? 20 : 0) + (m.summary ? 15 : 0) + (m.shared ? 15 : 0) + filesDone * 6; // ≤ 80
  const baseComplete = base >= 80;
  const publishCounts = baseComplete && !!m.published;
  const pct = Math.min(100, base + (publishCounts ? 20 : 0));
  const items = MASTERY_STEPS.map((s) => {
    if (s.key === 'files') return { ...s, done: files >= 5, count: files, frac: filesDone + '/5' };
    if (s.key === 'published') return { ...s, done: publishCounts, locked: !baseComplete, flagged: !!m.published };
    return { ...s, done: !!m[s.key] };
  });
  return { pct, base, baseComplete, files, items, published: !!m.published };
}

// Live hook: re-reads whenever mastery, reviews, files, or focus change.
function useMastery(topicId) {
  const [v, setV] = React.useState(() => computeMastery(topicId));
  React.useEffect(() => {
    const r = () => setV(computeMastery(topicId));
    r();
    const evts = ['pl-mastery', 'pl-reviewed', 'pl-files', 'focus', 'storage'];
    evts.forEach((e) => window.addEventListener(e, r));
    return () => evts.forEach((e) => window.removeEventListener(e, r));
  }, [topicId]);
  return v;
}

// ---- Share modal: pick friends to share this topic's materials with --------
function ShareTopicModal({ topic, onClose, onShared }) {
  const friends = window.FRIENDS || [];
  const [picked, setPicked] = React.useState([]);
  const toggle = (id) => setPicked((p) => p.includes(id) ? p.filter((x) => x !== id) : [...p, id]);
  return (
    <div className="scrim" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 440 }}>
        <div className="mhead">
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span className="itile" style={{ width: 32, height: 32, borderRadius: 9, background: 'var(--surface-2)', color: 'var(--ink-2)' }}><Icon name="users" size={17} /></span>
            <span style={{ fontWeight: 600, fontSize: 16 }}>Share “{topic.name}”</span>
          </div>
          <button className="icon-btn" style={{ width: 32, height: 32, border: 'none' }} onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="mbody" style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          <div className="t-small" style={{ marginBottom: 4 }}>Share this topic’s summary, concept map, and decks. Pick who can follow along.</div>
          {friends.length === 0 && <div style={{ fontSize: 13, color: 'var(--ink-3)', padding: '8px 2px' }}>No friends yet.</div>}
          {friends.map((f) => {
            const on = picked.includes(f.id);
            return (
              <button key={f.id} className="conn-row" onClick={() => toggle(f.id)} style={{ padding: '10px 12px', cursor: 'pointer', textAlign: 'left', border: on ? '1.5px solid var(--blue)' : '1px solid var(--line)', background: on ? 'color-mix(in srgb,var(--blue) 7%, var(--paper))' : 'var(--paper)' }}>
                <FriendAvatar name={f.name} accent={f.accent} size={34} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 14, fontWeight: 600 }}>{f.name}</div>
                  <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)' }}>{(f.headline || f.field || '').slice(0, 38)}</div>
                </div>
                <span aria-hidden="true" style={{ width: 20, height: 20, borderRadius: 99, flex: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', border: on ? 'none' : '1.5px solid var(--line-strong)', background: on ? 'var(--blue)' : 'transparent', color: '#fff' }}>{on ? <Icon name="check" size={13} /> : null}</span>
              </button>);
          })}
        </div>
        <div className="mfoot" style={{ justifyContent: 'flex-end', gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn blue" disabled={!picked.length} onClick={() => onShared(picked.length)}><Icon name="arrow-up-right" size={15} /> Share with {picked.length || ''}{picked.length === 1 ? ' friend' : picked.length ? ' friends' : ''}</button>
        </div>
      </div>
    </div>);
}

// ---- Publish modal: publish original work others can save as reference -----
function PublishModal({ topic, onClose, onPublished }) {
  const [title, setTitle] = React.useState('');
  const [kind, setKind] = React.useState('guide');
  const [desc, setDesc] = React.useState('');
  const [file, setFile] = React.useState(null);
  const fileRef = React.useRef(null);
  const KINDS = [['guide', 'Study guide'], ['notes', 'Original notes'], ['deck', 'Custom deck'], ['essay', 'Write-up']];
  const fmtSize = (b) => b == null ? '' : b < 1024 ? b + ' B' : b < 1048576 ? (b / 1024).toFixed(0) + ' KB' : (b / 1048576).toFixed(1) + ' MB';
  return (
    <div className="scrim" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 460 }}>
        <div className="mhead">
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span className="itile" style={{ width: 32, height: 32, borderRadius: 9, background: 'color-mix(in srgb,var(--blue) 14%, var(--paper))', color: 'var(--blue-ink)' }}><Icon name="sparkles" size={17} /></span>
            <span style={{ fontWeight: 600, fontSize: 16 }}>Publish original material</span>
          </div>
          <button className="icon-btn" style={{ width: 32, height: 32, border: 'none' }} onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="mbody" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="t-small">Share your own work on <strong>{topic.name}</strong> with the community — other learners can save it as a reference. This is the final step to 100% mastery.</div>
          <div>
            <label className="field-label">Title</label>
            <input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder={'e.g. ' + topic.name + ' — my field-tested study guide'} />
          </div>
          <div>
            <label className="field-label">Type</label>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {KINDS.map(([id, lab]) =>
              <button key={id} className={'chip' + (kind === id ? ' on' : '')} onClick={() => setKind(id)}>{lab}</button>)}
            </div>
          </div>
          <div>
            <label className="field-label">What’s in it?</label>
            <textarea className="input" rows={3} value={desc} onChange={(e) => setDesc(e.target.value)} placeholder="A sentence or two so others know what they’re saving…" style={{ resize: 'vertical', minHeight: 64 }} />
          </div>
          <div>
            <label className="field-label">Attach your file</label>
            <input type="file" ref={fileRef} style={{ display: 'none' }} accept=".pdf,.doc,.docx,.txt,.md,.png,.jpg,.jpeg,.ppt,.pptx,.csv"
              onChange={(e) => { const f = e.target.files && e.target.files[0]; if (f) setFile(f); }} />
            {!file ?
            <button type="button" onClick={() => fileRef.current && fileRef.current.click()}
              style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, padding: '18px 16px', borderRadius: 12, border: '1.5px dashed var(--line-strong)', background: 'var(--surface-2)', cursor: 'pointer', color: 'var(--ink-3)' }}>
                <Icon name="download" size={20} style={{ transform: 'rotate(180deg)', color: 'var(--blue-ink)' }} />
                <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-2)' }}>Upload the file you’re sharing</span>
                <span style={{ fontSize: 11.5, textAlign: 'center' }}>PDF, Word, slides, text, or an image — others can save it</span>
              </button> :
            <div className="lrow" style={{ alignItems: 'center', border: '1px solid var(--line)', borderRadius: 'var(--r-md)', padding: '10px 12px', background: 'var(--paper)' }}>
                <span className="thumb" style={{ width: 34, height: 34, background: 'var(--surface-2)', color: 'var(--blue-ink)' }}><Icon name="book" size={16} /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{file.name}</div>
                  <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>{fmtSize(file.size)} · ready to share</div>
                </div>
                <button className="icon-btn" style={{ width: 28, height: 28, border: 'none', flex: 'none' }} title="Remove file" onClick={() => { setFile(null); if (fileRef.current) fileRef.current.value = ''; }}><Icon name="x" size={15} /></button>
              </div>}
          </div>
        </div>
        <div className="mfoot" style={{ justifyContent: 'flex-end', gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn blue" disabled={!title.trim()} onClick={() => onPublished({ title: title.trim(), kind, desc: desc.trim(), file: file ? file.name : null })}><Icon name="arrow-up-right" size={15} /> Publish</button>
        </div>
      </div>
    </div>);
}

// ---- The mastery breakdown panel shown on a topic page ---------------------
function MasteryPanel({ topicId, topic, mats, openMaterial, openGenerate, toast }) {
  const ms = useMastery(topicId);
  const [share, setShare] = React.useState(false);
  const [publish, setPublish] = React.useState(false);
  const deck = mats.find((m) => m.type === 'deck');
  const summary = mats.find((m) => m.type === 'summary');

  const act = (key) => {
    if (key === 'deck') { deck ? openMaterial(deck.id) : openGenerate(topicId, 'deck'); }
    else if (key === 'summary') { summary ? openMaterial(summary.id) : openGenerate(topicId, 'summary'); }
    else if (key === 'shared') { setShare(true); }
    else if (key === 'files') { try { window.dispatchEvent(new CustomEvent('pl-open-upload', { detail: { topicId } })); } catch (e) {} }
    else if (key === 'published') { setPublish(true); }
  };
  const cta = { deck: deck ? 'Review' : 'Generate', summary: summary ? 'Listen' : 'Generate', shared: 'Share', files: 'Upload', published: 'Publish' };

  return (
    <div className="card pad mastery-panel">
      <div className="section-title" style={{ marginBottom: 4 }}>
        <h2><Icon name="trending" size={17} style={{ color: 'var(--ink-3)' }} /> Mastery</h2>
        <span className="mastery-pct">{ms.pct}%</span>
      </div>
      <div className="mastery-track">
        <i style={{ width: ms.pct + '%' }} />
        <span className="mastery-gate" style={{ left: '80%' }} title="80% — needs 5 files" />
      </div>
      <div className="mono mastery-cap">{ms.pct < 80 ? 'Study + 5 uploaded files unlock 80%' : ms.pct < 100 ? 'Publish your own material to reach 100%' : 'Topic mastered — your material is live for others'}</div>

      <div className="mastery-steps">
        {ms.items.map((s) => {
          const locked = s.locked;
          return (
            <div key={s.key} className={'mastery-step' + (s.done ? ' done' : '') + (locked ? ' locked' : '')}>
              <span className="ms-check">{s.done ? <Icon name="check" size={14} /> : locked ? <Icon name="lock" size={13} /> : <Icon name={s.icon} size={15} />}</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="ms-label">{s.label}{s.key === 'files' && <span className="ms-frac">{s.frac}</span>}</div>
                <div className="ms-hint">{locked ? 'Unlocks at 80% mastery' : s.hint}</div>
              </div>
              <span className="ms-weight">+{s.weight}%</span>
              {s.done ?
              <span className="ms-actiondone"><Icon name="check" size={14} /></span> :
              <button className="btn sm" disabled={locked} onClick={() => act(s.key)}>{cta[s.key]}</button>}
            </div>);
        })}
      </div>

      {share &&
      <ShareTopicModal topic={topic} onClose={() => setShare(false)} onShared={(n) => { setMasteryFlag(topicId, 'shared', true); setShare(false); toast && toast('Shared “' + topic.name + '” with ' + n + (n === 1 ? ' friend' : ' friends')); }} />}
      {publish &&
      <PublishModal topic={topic} onClose={() => setPublish(false)} onPublished={(work) => {
        try { const list = JSON.parse(localStorage.getItem('pl-published') || '[]'); list.unshift({ topicId, topic: topic.name, ...work, at: Date.now() }); localStorage.setItem('pl-published', JSON.stringify(list)); } catch (e) {}
        setMasteryFlag(topicId, 'published', true);
        setPublish(false);
        toast && toast('Published — others can now save “' + work.title + '”');
      }} />}
    </div>);
}

Object.assign(window, { MASTERY_STEPS, getMastery, setMasteryFlag, computeMastery, useMastery, MasteryPanel, ShareTopicModal, topicFileCount });
