// Ideas.jsx — "Idea board": browse suggested learning tasks, select several as
// goals, add your own, and collect your own notes & links for each goal.

const IDEA_SEED = [
{ id: 'i-photo', domain: 'bio', title: 'Photosynthesis, end to end', blurb: 'How plants turn sunlight, water, and air into sugar.' },
{ id: 'i-exo', domain: 'astro', title: 'Hunting for exoplanets', blurb: 'How we find and read worlds around other stars.' },
{ id: 'i-aqua', domain: 'rome', title: 'Roman aqueducts & engineering', blurb: 'How Rome moved water across mountains and miles.' },
{ id: 'i-trans', domain: 'ml', title: 'How transformers power LLMs', blurb: 'Attention, tokens, and the modern AI stack.' },
{ id: 'i-silk', domain: 'hist', title: 'The Silk Road', blurb: 'The trade routes that linked distant civilizations.' },
{ id: 'i-rhythm', domain: 'mus', title: 'Rhythm, meter & syncopation', blurb: 'How time signatures give music its groove.' },
{ id: 'i-subj', domain: 'esp', title: 'The Spanish subjunctive', blurb: 'Expressing doubt, wishes, and emotion.' },
{ id: 'i-sky', domain: 'sci', title: 'Why the sky is blue', blurb: 'How sunlight scatters in the atmosphere.' },
{ id: 'i-gps', domain: 'tech', title: 'How GPS finds you', blurb: 'Satellites, precise timing, and trilateration.' }];


const ideaAccent = (domain) => (domainById(domain) || {}).accent || 'var(--blue)';
const ideaTag = (domain) => (domainById(domain) || {}).name || 'Idea';

function IdeaBoard({ toast, openGenerate }) {
  const load = (k, fb) => {try {return JSON.parse(localStorage.getItem(k)) || fb;} catch (e) {return fb;}};
  const [custom, setCustom] = React.useState(() => load('pl-idea-custom', []));
  const [goals, setGoals] = React.useState(() => load('pl-goals', []));
  const [sel, setSel] = React.useState(() => new Set());
  const [draft, setDraft] = React.useState('');
  const [draftDom, setDraftDom] = React.useState('sci');
  const [openGoal, setOpenGoal] = React.useState(null);
  // Newly captured ideas glow until the user hovers them (so they're easy to spot).
  const [newIds, setNewIds] = React.useState(() => new Set(load('pl-idea-new', [])));
  // Inline edits to any idea's words (title/blurb), keyed by idea id, persisted.
  const [edits, setEdits] = React.useState(() => load('pl-idea-edits', {}));
  const persistEdits = (obj) => {setEdits(obj);try {localStorage.setItem('pl-idea-edits', JSON.stringify(obj));} catch (e) {}};
  const titleOf = (i) => (edits[i.id] && edits[i.id].title != null) ? edits[i.id].title : i.title;
  const blurbOf = (i) => (edits[i.id] && edits[i.id].blurb != null) ? edits[i.id].blurb : i.blurb;
  const editField = (id, field, val) => {const cur = edits[id] || {};persistEdits({ ...edits, [id]: { ...cur, [field]: val } });};

  const persistCustom = (list) => {setCustom(list);try {localStorage.setItem('pl-idea-custom', JSON.stringify(list));} catch (e) {}};
  const persistGoals = (list) => {setGoals(list);try {localStorage.setItem('pl-goals', JSON.stringify(list));} catch (e) {}};

  // Reflect notes captured via Quick capture while this page is already open,
  // and make the fresh card glow.
  React.useEffect(() => {
    const onAdd = (e) => {
      setCustom(load('pl-idea-custom', []));
      const id = e && e.detail && e.detail.id;
      if (id) setNewIds((s) => new Set(s).add(id));
    };
    window.addEventListener('pl-idea-added', onAdd);
    return () => window.removeEventListener('pl-idea-added', onAdd);
  }, []);

  // Once a glowing card is hovered, it has been "seen" — drop the highlight for good.
  const clearNew = (id) => {
    if (!newIds.has(id)) return;
    setNewIds((s) => {const n = new Set(s);n.delete(id);return n;});
    try {
      const rest = load('pl-idea-new', []).filter((x) => x !== id);
      localStorage.setItem('pl-idea-new', JSON.stringify(rest));
    } catch (e) {}
  };

  const ideas = [...IDEA_SEED, ...custom];
  const goalIdeaIds = new Set(goals.map((g) => g.ideaId).filter(Boolean));

  const toggle = (id) => {
    if (goalIdeaIds.has(id)) return;
    setSel((s) => {const n = new Set(s);n.has(id) ? n.delete(id) : n.add(id);return n;});
  };
  const addCustom = () => {
    const title = draft.trim();
    if (!title) return;
    const idea = { id: 'i-c' + Date.now(), domain: draftDom, title, blurb: 'Your own idea to explore.', custom: true };
    persistCustom([idea, ...custom]);
    setSel((s) => new Set(s).add(idea.id));
    setDraft('');
  };
  const removeCustom = (id) => {persistCustom(custom.filter((c) => c.id !== id));setSel((s) => {const n = new Set(s);n.delete(id);return n;});};

  const commitGoals = () => {
    const picks = ideas.filter((i) => sel.has(i.id));
    if (!picks.length) return;
    const added = picks.map((i) => ({
      id: 'g' + Date.now() + Math.random().toString(36).slice(2, 6),
      ideaId: i.id, title: titleOf(i), blurb: blurbOf(i), domain: i.domain,
      notes: '', links: [], done: false, created: Date.now()
    }));
    persistGoals([...added, ...goals]);
    setSel(new Set());
    if (toast) toast(added.length === 1 ? 'Added 1 goal' : 'Added ' + added.length + ' goals');
  };

  const patchGoal = (id, patch) => persistGoals(goals.map((g) => g.id === id ? { ...g, ...patch } : g));
  const removeGoal = (id) => {persistGoals(goals.filter((g) => g.id !== id));if (openGoal === id) setOpenGoal(null);};

  const doneCount = goals.filter((g) => g.done).length;

  return (
    <div className="idea-board">
      <div className="idea-grid">
        {ideas.map((i) => {
          const on = sel.has(i.id);
          const isGoal = goalIdeaIds.has(i.id);
          const ac = ideaAccent(i.domain);
          const isNew = newIds.has(i.id) && !on;
          return (
            <div key={i.id} className={'idea-card' + (on ? ' on' : '') + (isGoal ? ' isgoal' : '') + (isNew ? ' isnew' : '')}
            onClick={() => toggle(i.id)} role="button" tabIndex={0}
            onMouseEnter={() => clearNew(i.id)} onFocus={() => clearNew(i.id)}
            onKeyDown={(e) => {if (e.key === 'Enter' || e.key === ' ') {e.preventDefault();toggle(i.id);}}}
            title={isGoal ? 'Already one of your goals' : on ? 'Selected — click to remove' : 'Click to select'}
            style={{ '--glow': ac, borderColor: on ? ac : undefined, boxShadow: on ? '0 0 0 2px ' + ac + '33' : undefined, cursor: isGoal ? 'default' : 'pointer' }}>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
                <span className="idea-tag"><span style={{ width: 8, height: 8, borderRadius: 99, background: ac }} /> {ideaTag(i.domain)}</span>
                <span className="idea-check" style={{ borderColor: on ? ac : 'var(--line-strong)', background: on ? ac : 'transparent' }}>
                  {on && <Icon name="check" size={13} style={{ color: '#fff' }} />}
                  {isGoal && !on && <Icon name="flag" size={12} style={{ color: ac }} />}
                </span>
              </div>
              <div className="idea-title" contentEditable suppressContentEditableWarning spellCheck={false}
              onMouseDown={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
              onKeyDown={(e) => {e.stopPropagation();if (e.key === 'Enter') {e.preventDefault();e.currentTarget.blur();}}}
              onBlur={(e) => editField(i.id, 'title', e.currentTarget.textContent.trim() || i.title)}>{titleOf(i)}</div>
              <div className="idea-blurb" contentEditable suppressContentEditableWarning spellCheck={false}
              onMouseDown={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
              onKeyDown={(e) => {e.stopPropagation();if (e.key === 'Enter') {e.preventDefault();e.currentTarget.blur();}}}
              onBlur={(e) => editField(i.id, 'blurb', e.currentTarget.textContent.trim() || i.blurb)}>{blurbOf(i)}</div>
              {isGoal && <div className="idea-goalbadge" style={{ color: ac }}><Icon name="check" size={12} /> In your goals</div>}
              {i.custom && !isGoal && <button className="icon-btn idea-del" title="Remove idea" onClick={(e) => {e.stopPropagation();removeCustom(i.id);}}><Icon name="trash" size={13} /></button>}
            </div>);

        })}
      </div>

      <div className="idea-add">
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <Icon name="plus" size={16} style={{ color: 'var(--ink-3)', flex: 'none' }} />
          <input className="input" value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => {if (e.key === 'Enter') addCustom();}}
          placeholder="Add your own idea to explore…" style={{ flex: 1, minWidth: 180 }} />
          <select className="input" value={draftDom} onChange={(e) => setDraftDom(e.target.value)} style={{ width: 'auto', flex: 'none', cursor: 'pointer' }}>
            {DOMAINS.map((d) => <option key={d.id} value={d.id}>{d.name}</option>)}
          </select>
          <button className="btn sm" onClick={addCustom} disabled={!draft.trim()}>Add idea</button>
        </div>
      </div>

      {sel.size > 0 &&
      <div className="idea-actionbar fade-up">
        <span style={{ fontSize: 13.5, fontWeight: 600 }}>{sel.size} idea{sel.size > 1 ? 's' : ''} selected</span>
        <div style={{ display: 'flex', gap: 8, marginLeft: 'auto' }}>
          <button className="btn sm" onClick={() => setSel(new Set())}>Clear</button>
          <button className="btn blue sm" onClick={commitGoals}><Icon name="flag" size={15} /> Set as goals</button>
        </div>
      </div>}

      <div className="section-title" style={{ marginTop: 30, marginBottom: 12 }}>
        <h2 style={{ fontSize: 17 }}><Icon name="flag" size={16} style={{ color: 'var(--clay, #C7937D)' }} /> My goals <span className="count-pill">{goals.length}</span></h2>
        {goals.length > 0 && <span className="mono" style={{ fontSize: 12, color: 'var(--ink-3)' }}>{doneCount}/{goals.length} done</span>}
      </div>

      {goals.length === 0 ?
      <div className="idea-empty">
        <span className="itile" style={{ width: 40, height: 40, borderRadius: 11, background: 'var(--surface-2)', color: 'var(--ink-3)' }}><Icon name="flag" size={19} /></span>
        <div style={{ fontSize: 13.5, fontWeight: 600, marginTop: 8 }}>No goals yet</div>
        <div className="t-small" style={{ maxWidth: 320, margin: '2px auto 0' }}>Select ideas above and hit “Set as goals” — each goal gives you a space to collect your own notes and links.</div>
      </div> :
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {goals.map((g) => {
          const ac = ideaAccent(g.domain);
          const open = openGoal === g.id;
          return (
            <div key={g.id} className={'goal-row' + (g.done ? ' done' : '')}>
              <div className="goal-head">
                <button className="goal-toggle" onClick={() => patchGoal(g.id, { done: !g.done })} title={g.done ? 'Mark not done' : 'Mark done'}
                style={{ borderColor: g.done ? 'var(--positive)' : 'var(--line-strong)', background: g.done ? 'var(--positive)' : 'transparent' }}>
                  {g.done && <Icon name="check" size={13} style={{ color: '#fff' }} />}
                </button>
                <div style={{ flex: 1, minWidth: 0, cursor: 'pointer' }} onClick={() => setOpenGoal(open ? null : g.id)}>
                  <div className="goal-title" style={{ textDecoration: g.done ? 'line-through' : 'none', opacity: g.done ? 0.6 : 1 }}>{g.title}</div>
                  <div className="goal-meta">
                    <span className="idea-tag"><span style={{ width: 7, height: 7, borderRadius: 99, background: ac }} /> {ideaTag(g.domain)}</span>
                    {g.links.length > 0 && <span><Icon name="link" size={12} /> {g.links.length}</span>}
                    {g.notes.trim() && <span><Icon name="book" size={12} /> notes</span>}
                  </div>
                </div>
                <button className="btn ghost sm" onClick={() => setOpenGoal(open ? null : g.id)}>{open ? 'Close' : 'Collect info'} <Icon name={open ? 'chevron-up' : 'chevron-down'} size={15} /></button>
                {g.done && openGenerate && <button className="btn blue sm" title="Generate study materials for this goal" onClick={(e) => {e.stopPropagation();openGenerate(null, undefined, g.title);}}><Icon name="sparkles" size={15} /> Generate materials</button>}
                <button className="icon-btn" style={{ width: 30, height: 30, border: 'none', flex: 'none' }} title="Remove goal" onClick={() => removeGoal(g.id)}><Icon name="trash" size={15} /></button>
              </div>
              {open &&
              <GoalCollect goal={g} onSave={(patch) => patchGoal(g.id, patch)} toast={toast} />}
            </div>);

        })}
      </div>}
    </div>);

}

// The per-goal "collect info" panel: a local draft of notes + a pending link,
// saved together with one explicit Save button.
function GoalCollect({ goal, onSave, toast }) {
  const [notes, setNotes] = React.useState(goal.notes || '');
  const [label, setLabel] = React.useState('');
  const [url, setUrl] = React.useState('');
  React.useEffect(() => {setNotes(goal.notes || '');}, [goal.id]);
  const dirty = notes !== (goal.notes || '') || !!url.trim();
  const save = () => {
    const patch = { notes };
    if (url.trim()) patch.links = [...goal.links, { label: label.trim(), url: url.trim() }];
    onSave(patch);
    setLabel('');setUrl('');
    if (toast) toast('Saved to “' + goal.title + '”');
  };
  return (
    <div className="goal-collect fade-up">
      <label className="field-label">What I’ve found</label>
      <textarea className="input" rows={3} value={notes} onChange={(e) => setNotes(e.target.value)}
      onKeyDown={(e) => {if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') save();}}
      placeholder="Jot down what you learn as you research this on your own…" style={{ resize: 'vertical', lineHeight: 1.5 }} />
      <label className="field-label" style={{ marginTop: 12 }}>Resources I’ve collected</label>
      {goal.links.length > 0 &&
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginBottom: 8 }}>
        {goal.links.map((l, k) =>
        <div key={k} className="goal-link">
          <Icon name="link" size={13} style={{ color: 'var(--ink-3)', flex: 'none' }} />
          <a href={/^https?:\/\//.test(l.url) ? l.url : 'https://' + l.url} target="_blank" rel="noreferrer" style={{ flex: 1, minWidth: 0, color: 'var(--blue-ink)', textDecoration: 'none', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{l.label || l.url}</a>
          <button className="icon-btn" style={{ width: 24, height: 24, border: 'none', flex: 'none' }} onClick={() => onSave({ links: goal.links.filter((_, j) => j !== k) })}><Icon name="x" size={13} /></button>
        </div>)}
      </div>}
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
        <input className="input" value={label} onChange={(e) => setLabel(e.target.value)} placeholder="Link title (optional)" style={{ flex: '1 1 130px', minWidth: 110 }} />
        <input className="input" value={url} onChange={(e) => setUrl(e.target.value)} placeholder="Paste a link…" style={{ flex: '2 1 200px', minWidth: 150 }} />
      </div>
      <div className="goal-save-row">
        <span className="t-small">{dirty ? 'Unsaved changes' : 'All changes saved'}</span>
        <button className="btn blue sm" onClick={save} disabled={!dirty}><Icon name="check" size={15} /> Save notes &amp; link</button>
      </div>
    </div>);

}

Object.assign(window, { IdeaBoard, GoalCollect });

// Voice notes: speak → transcribe → save into a list, persisted on this page.
function VoiceNotes({ toast }) {
  const load = () => {try {return JSON.parse(localStorage.getItem('pl-voice-notes')) || [];} catch (e) {return [];}};
  const [text, setText] = React.useState('');
  const [listening, setListening] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [notes, setNotes] = React.useState(load);
  const recRef = React.useRef(null);
  const baseRef = React.useRef('');
  const SR = typeof window !== 'undefined' && (window.SpeechRecognition || window.webkitSpeechRecognition);
  const persist = (list) => {setNotes(list);try {localStorage.setItem('pl-voice-notes', JSON.stringify(list));} catch (e) {}};
  const stop = () => {try {recRef.current && recRef.current.stop();} catch (e) {}setListening(false);};
  const start = () => {
    if (!SR) {setErr('Voice input isn’t supported in this browser.');return;}
    setErr('');
    try {
      const rec = new SR();
      rec.lang = 'en-US';rec.continuous = true;rec.interimResults = true;
      baseRef.current = text ? text.replace(/\s*$/, '') + ' ' : '';
      rec.onresult = (e) => {
        let interim = '',finalAdd = '';
        for (let k = e.resultIndex; k < e.results.length; k++) {
          const tr = e.results[k];
          if (tr.isFinal) finalAdd += tr[0].transcript;else interim += tr[0].transcript;
        }
        if (finalAdd) baseRef.current = (baseRef.current + finalAdd).replace(/\s{2,}/g, ' ');
        setText((baseRef.current + interim).replace(/\s{2,}/g, ' '));
      };
      rec.onerror = (e) => {setErr(e.error === 'not-allowed' ? 'Microphone access was blocked.' : 'Couldn’t capture audio.');setListening(false);};
      rec.onend = () => setListening(false);
      recRef.current = rec;rec.start();setListening(true);
    } catch (e) {setErr('Couldn’t start the microphone.');setListening(false);}
  };
  React.useEffect(() => () => {try {recRef.current && recRef.current.stop();} catch (e) {}}, []);
  const save = () => {
    const t = text.trim();if (!t) return;
    stop();
    persist([{ id: 'vn' + Date.now(), text: t, created: Date.now() }, ...notes]);
    setText('');baseRef.current = '';
    if (toast) toast('Voice note saved');
  };
  const remove = (id) => persist(notes.filter((n) => n.id !== id));
  const fmt = (ts) => {const d = new Date(ts);return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) + ' · ' + d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });};

  return (
    <div className="card pad" style={{ marginBottom: 20 }}>
      <div className="section-title" style={{ marginBottom: 4 }}>
        <h2 style={{ fontSize: 17 }}><Icon name="mic" size={17} style={{ color: 'var(--blue-ink)' }} /> Capture a note by voice</h2>
        {listening && <span className="t-small" style={{ display: 'inline-flex', alignItems: 'center', gap: 7, color: 'var(--critical)' }}><span className="rec-dot" /> Listening…</span>}
      </div>
      <p className="t-small" style={{ marginTop: 0, marginBottom: 12 }}>Tap Speak and talk — your words are transcribed below. Edit if needed, then save it to your notes.</p>
      <textarea className="input" rows={3} value={text} onChange={(e) => setText(e.target.value)}
      placeholder="Your spoken note will appear here…" style={{ resize: 'vertical', lineHeight: 1.5, width: '100%' }} />
      {err && <div className="t-small" style={{ marginTop: 6, color: 'var(--critical)' }}>{err}</div>}
      <div style={{ display: 'flex', gap: 8, marginTop: 10, flexWrap: 'wrap' }}>
        <button type="button" className="btn" onClick={() => listening ? stop() : start()}
        style={listening ? { background: 'var(--critical)', borderColor: 'var(--critical)', color: '#fff' } : undefined}>
          <Icon name="mic" size={16} /> {listening ? 'Stop recording' : 'Speak'}
        </button>
        {text && <button type="button" className="btn" onClick={() => {setText('');baseRef.current = '';}}><Icon name="x" size={15} /> Clear</button>}
        <button type="button" className="btn primary" style={{ marginLeft: 'auto' }} disabled={!text.trim()} onClick={save}><Icon name="check" size={16} /> Save note</button>
      </div>

      <div className="section-title" style={{ marginTop: 22, marginBottom: 12 }}>
        <h2 style={{ fontSize: 15 }}><Icon name="book" size={15} style={{ color: 'var(--ink-3)' }} /> Saved voice notes <span className="count-pill">{notes.length}</span></h2>
      </div>
      {notes.length === 0 ?
      <div className="idea-empty" style={{ paddingTop: 12, paddingBottom: 30 }}>
        <div style={{ fontSize: 13.5, fontWeight: 600, marginTop: 8 }}>No voice notes yet</div>
        <div className="t-small" style={{ maxWidth: 320, margin: '2px auto 0', width: "600px" }}>Record a thought above and save it. it’ll appear here.</div>
      </div> :
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {notes.map((n) =>
        <div key={n.id} className="goal-row" style={{ padding: '12px 14px', display: 'flex', alignItems: 'flex-start', gap: 11 }}>
          <span className="itile" style={{ width: 30, height: 30, borderRadius: 8, background: 'color-mix(in srgb,var(--blue) 12%, var(--paper))', color: 'var(--blue-ink)', flex: 'none' }}><Icon name="mic" size={15} /></span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 14, lineHeight: 1.5, whiteSpace: 'pre-wrap' }}>{n.text}</div>
            <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>{fmt(n.created)}</div>
          </div>
          <button className="icon-btn" style={{ width: 30, height: 30, border: 'none', flex: 'none' }} title="Delete note" onClick={() => remove(n.id)}><Icon name="trash" size={15} /></button>
        </div>)}
      </div>}
    </div>);

}
window.VoiceNotes = VoiceNotes;

// Full page reached from the "Ideas" icon in the nav.
function IdeasPage({ toast, openGenerate }) {
  return (
    <div className="content-pad fade-up">
      <div className="page-head" style={{ marginBottom: 20 }}>
        <div>
          <p className="eyebrow">Explore</p>
          <h1>Ideas</h1>
          <p className="sub">Pick new things you want to learn, set them as goals, and collect what you find on your own.</p>
        </div>
      </div>
      <VoiceNotes toast={toast} />
      <div className="card pad">
        <IdeaBoard toast={toast} openGenerate={openGenerate} />
      </div>
    </div>);

}
window.IdeasPage = IdeasPage;