// Notes — live lecture sessions + real audio recording + upload
const { useState: nUseState, useEffect: nUseEffect, useRef: nUseRef, useMemo: nUseMemo } = React;

function openNotion(url) {
  window.open(url || NOTION_BASE, '_blank', 'noopener');
}

function Notes({ goto }) {
  const [lectures, setLectures] = nUseState([]);
  const [loading, setLoading] = nUseState(true);
  const [active, setActive] = nUseState('all');

  nUseEffect(() => {
    loadSessions();
  }, []);

  function loadSessions() {
    fnGetCached('lecture-sessions', 60_000)
      .then(r => {
        const list = (r.sessions || []).map(transformLecture);
        setLectures(list);
        window.LECTURES = list;
      })
      .catch(e => console.error('lecture-sessions:', e))
      .finally(() => setLoading(false));
  }

  const filtered = nUseMemo(
    () => active === 'all' ? lectures : lectures.filter(l => l.subject === active),
    [lectures, active]
  );

  return (
    <>
      <Topbar
        crumbs={['Notes', active === 'all' ? 'All' : (SUBJ_BY_ID[active]?.short ?? active)]}
        actions={<>
          <button className="btn primary" onClick={() => goto('new-lecture')}>
            <I.Plus size={11} strokeWidth={2.6} /> New Lecture
          </button>
        </>}
      />

      <div className="notes-layout">
        <aside className="subjects-col">
          <div className={`subj-row ${active === 'all' ? 'active' : ''}`} onClick={() => setActive('all')}>
            <I.Layers size={12} /><span>All</span><span className="count">{lectures.length}</span>
          </div>
          <div style={{ height: 8 }} />
          <div style={{ fontSize: 10.5, color: 'var(--fg-3)', padding: '4px 10px 2px', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 500 }}>Subjects</div>
          {VISIBLE_SUBJECTS.map(s => {
            const c = lectures.filter(l => l.subject === s.id).length;
            return (
              <div key={s.id} className={`subj-row ${active === s.id ? 'active' : ''}`} onClick={() => setActive(s.id)}>
                <span className="subj-dot" style={{ background: s.hex }} /><span>{s.short}</span>
                <span className="count">{c}</span>
              </div>
            );
          })}
        </aside>

        <div className="feed-col">
          <div className="section-header">
            <div>
              <div className="section-title">{active === 'all' ? 'Lectures' : (SUBJ_BY_ID[active]?.name ?? active)}</div>
              <div className="section-sub">{filtered.length} lecture{filtered.length === 1 ? '' : 's'} · notes open in Notion</div>
            </div>
          </div>

          {loading && <div className="empty" style={{ padding: 48 }}><span className="spinner" /> Loading…</div>}

          {!loading && groupByDate(filtered).map(([date, arr]) => (
            <div key={date} style={{ marginBottom: 18 }}>
              <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginBottom: 4, textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }}>{date}</div>
              <div style={{ borderTop: '1px solid var(--border)' }}>
                {arr.map(l => (
                  <div key={l.id} className="lec-row" onClick={() => openNotion(l.notionUrl)}>
                    <div className="bar" style={{ background: (SUBJ_BY_ID[l.subject] || SUBJ_BY_ID.maths).hex }} />
                    <div style={{ minWidth: 0 }}>
                      <div className="lec-title ellipsis">{l.title}</div>
                      <div className="lec-meta" style={{ marginTop: 3 }}>
                        <SubjectTag subject={l.subject} />
                        <span className="faint">·</span>
                        <span>{l.duration}</span>
                      </div>
                    </div>
                    {l.status === 'processing' ? (
                      <span className="hstack" style={{ gap: 5, color: 'var(--fg-2)', fontSize: 11 }}>
                        <span className="spinner" /> Processing
                      </span>
                    ) : (
                      <span className="badge"><span className="nc-mark" style={{ width: 9, height: 9, fontSize: 7 }}>N</span> Notion</span>
                    )}
                    <I.External size={11} className="faint" />
                  </div>
                ))}
              </div>
            </div>
          ))}

          {!loading && filtered.length === 0 && (
            <div className="empty">No lectures yet. Start a recording above.</div>
          )}
        </div>
      </div>
    </>
  );
}

function groupByDate(arr) {
  const map = new Map();
  for (const l of arr) {
    const key = l.date || 'Unknown';
    if (!map.has(key)) map.set(key, []);
    map.get(key).push(l);
  }
  return [...map.entries()];
}

// New Lecture setup page
function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result.split(',')[1]);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

function NewLecture({ goto, onStart }) {
  const [subject, setSubject] = nUseState('physics');
  const [title, setTitle] = nUseState(autoTitle('physics'));
  const [postQuery, setPostQuery] = nUseState('');
  const [selectedPosts, setSelectedPosts] = nUseState([]);
  const [pointers, setPointers] = nUseState('');
  const [attachments, setAttachments] = nUseState([]);
  const [pasteText, setPasteText] = nUseState('');
  const fileInputRef = nUseRef(null);

  async function handleFiles(fileList) {
    const files = Array.from(fileList).filter(
      f => f.type === 'application/pdf' || f.type.startsWith('image/')
    );
    const converted = await Promise.all(files.map(async f => ({
      name: f.name,
      base64: await fileToBase64(f),
      media_type: f.type,
    })));
    setAttachments(a => [...a, ...converted]);
  }

  function handleDrop(e) {
    e.preventDefault();
    handleFiles(e.dataTransfer.files);
  }

  const posts = window.CLASSROOM_POSTS || [];
  const todayPosts = posts.filter(p => p.date && p.date.startsWith('Today'));
  const filteredPosts = todayPosts.filter(p =>
    !postQuery ||
    p.title.toLowerCase().includes(postQuery.toLowerCase()) ||
    (SUBJ_BY_ID[p.subject]?.short || '').toLowerCase().includes(postQuery.toLowerCase())
  );
  const togglePost = (id) => setSelectedPosts(s => s.includes(id) ? s.filter(x => x !== id) : [...s, id]);
  const onSubjectChange = (s) => { setSubject(s); setTitle(autoTitle(s)); };

  return (
    <>
      <Topbar
        crumbs={[
          <span key="b" style={{ cursor: 'pointer' }} onClick={() => goto('notes')}>Notes</span>,
          'New Lecture',
        ]}
        actions={<button className="btn ghost" onClick={() => goto('notes')}>Cancel</button>}
      />
      <div className="content">
        <div className="nl-page">
          <div className="nl-eyebrow">New lecture</div>
          <input
            className="input xl"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            placeholder="Lecture title…"
          />
          <div className="hstack" style={{ marginTop: 8 }}>
            <SubjectInline value={subject} onChange={onSubjectChange} />
            <span className="dim" style={{ fontSize: 12 }}>
              · {new Date().toLocaleDateString('en', { weekday: 'long', day: 'numeric', month: 'long' })}
            </span>
          </div>

          {todayPosts.length > 0 && (
            <div className="nl-section">
              <div className="nl-section-title">Classroom posts</div>
              <div className="nl-section-help">Attach today's posts as context for the note taker.</div>
              {selectedPosts.length > 0 && (
                <div className="hstack" style={{ flexWrap: 'wrap', gap: 5, marginBottom: 8 }}>
                  {selectedPosts.map(id => {
                    const p = posts.find(x => x.id === id);
                    if (!p) return null;
                    return (
                      <span key={id} className="chip">
                        <span className="subj-dot" style={{ background: (SUBJ_BY_ID[p.subject] || SUBJ_BY_ID.maths).hex }} />
                        <span className="ellipsis" style={{ maxWidth: 240 }}>{p.title}</span>
                        <span className="x" onClick={() => togglePost(id)}><I.X size={10} /></span>
                      </span>
                    );
                  })}
                </div>
              )}
              <div className="hstack" style={{ marginBottom: 6, padding: '6px 9px', border: '1px solid var(--border-2)', borderRadius: 'var(--r-2)', background: 'var(--bg)' }}>
                <I.Search size={12} className="dim" />
                <input
                  style={{ flex: 1, fontSize: 12.5 }}
                  placeholder="Search today's posts…"
                  value={postQuery}
                  onChange={(e) => setPostQuery(e.target.value)}
                />
              </div>
              <div className="search-list">
                {filteredPosts.map(p => {
                  const sel = selectedPosts.includes(p.id);
                  return (
                    <div key={p.id} className={`search-list-row ${sel ? 'selected' : ''}`} onClick={() => togglePost(p.id)}>
                      <Checkbox checked={sel} onChange={() => togglePost(p.id)} />
                      <div style={{ minWidth: 0 }}>
                        <div className="hstack" style={{ gap: 6 }}>
                          <SubjectTag subject={p.subject} withName={false} />
                          <span className="ellipsis" style={{ color: 'var(--fg)' }}>{p.title}</span>
                        </div>
                        <div className="dim" style={{ fontSize: 11 }}>{p.teacher} · {p.date}</div>
                      </div>
                      <Badge>{p.type}</Badge>
                    </div>
                  );
                })}
                {filteredPosts.length === 0 && (
                  <div className="empty" style={{ padding: 18, fontSize: 11.5 }}>
                    {todayPosts.length === 0 ? 'No classroom posts loaded.' : 'No matching posts.'}
                  </div>
                )}
              </div>
            </div>
          )}

          <div className="nl-section">
            <div className="nl-section-title">Pointers <span className="dim" style={{ fontWeight: 400 }}>· optional</span></div>
            <div className="nl-section-help">Tell the note taker what to focus on or skip.</div>
            <textarea
              className="textarea"
              rows={3}
              placeholder={`e.g. "Focus on Newton's third law" or "Skip the first 10 minutes"`}
              value={pointers}
              onChange={(e) => setPointers(e.target.value)}
            />
          </div>

          <div className="nl-section">
            <div className="nl-section-title">Extra material <span className="dim" style={{ fontWeight: 400 }}>· optional</span></div>
            <div className="nl-section-help">Attach PDFs, photos, or paste text — all get indexed and cross-referenced with your notes.</div>
            <div
              className="attach-zone"
              onClick={() => fileInputRef.current?.click()}
              onDrop={handleDrop}
              onDragOver={(e) => e.preventDefault()}
            >
              <I.Paperclip size={12} className="dim" />
              <span className="dim" style={{ fontSize: 12 }}>Drop PDFs or photos here, or click to browse</span>
              <input
                ref={fileInputRef}
                type="file"
                accept=".pdf,image/*"
                multiple
                style={{ display: 'none' }}
                onChange={(e) => handleFiles(e.target.files)}
              />
            </div>
            {attachments.length > 0 && (
              <div className="hstack" style={{ flexWrap: 'wrap', gap: 5, marginTop: 6 }}>
                {attachments.map((a, i) => (
                  <span key={i} className="chip">
                    <I.File size={10} />
                    <span className="ellipsis" style={{ maxWidth: 180 }}>{a.name}</span>
                    <span className="x" onClick={() => setAttachments(arr => arr.filter((_, j) => j !== i))}>
                      <I.X size={10} />
                    </span>
                  </span>
                ))}
              </div>
            )}
            <textarea
              className="textarea"
              style={{ marginTop: 8 }}
              rows={3}
              placeholder="Paste textbook excerpts, handout text, or any extra context…"
              value={pasteText}
              onChange={(e) => setPasteText(e.target.value)}
            />
          </div>

          <div style={{ marginTop: 36, paddingTop: 18, borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 12 }}>
            <span className="dim" style={{ fontSize: 12 }}>
              {selectedPosts.length > 0 ? `${selectedPosts.length} post${selectedPosts.length === 1 ? '' : 's'} attached` : 'No posts attached'}
              {attachments.length > 0 ? ` · ${attachments.length} file${attachments.length === 1 ? '' : 's'}` : ''}
              {pasteText ? ' · text added' : ''}
              {pointers ? ' · pointers added' : ''}
            </span>
            <div style={{ flex: 1 }} />
            <button className="btn xl danger" onClick={() => onStart({ subject, title, selectedPosts, pointers, attachments, pasteText })}>
              <I.Mic size={13} /> Start Recording
            </button>
          </div>
        </div>
      </div>
    </>
  );
}

function SubjectInline({ value, onChange }) {
  const [open, setOpen] = nUseState(false);
  const cur = SUBJ_BY_ID[value] || SUBJ_BY_ID.maths;
  return (
    <div style={{ position: 'relative' }}>
      <button
        className="hstack"
        style={{ padding: '4px 8px', border: '1px solid var(--border-2)', borderRadius: 'var(--r-2)', fontSize: 12, background: 'var(--bg)' }}
        onClick={() => setOpen(o => !o)}
      >
        <span className="subj-dot" style={{ background: cur.hex }} />
        <span>{cur.short || cur.name}</span>
        <I.ChevronDown size={10} className="dim" />
      </button>
      {open && (
        <div style={{ position: 'absolute', top: '100%', left: 0, marginTop: 4, background: 'var(--bg-elev)', border: '1px solid var(--border-2)', borderRadius: 'var(--r-2)', padding: 4, zIndex: 10, minWidth: 180, boxShadow: 'var(--shadow-md)' }}>
          {VISIBLE_SUBJECTS.map(s => (
            <div
              key={s.id}
              className="hstack"
              style={{ padding: '5px 8px', borderRadius: 4, cursor: 'pointer', fontSize: 12.5, background: value === s.id ? 'var(--bg-2)' : 'transparent' }}
              onClick={() => { onChange(s.id); setOpen(false); }}
            >
              <span className="subj-dot" style={{ background: s.hex }} />
              <span>{s.short || s.name}</span>
              {value === s.id && <I.Check size={11} style={{ marginLeft: 'auto' }} />}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function autoTitle(subject) {
  const today = new Date();
  const date = `${today.getDate()} ${today.toLocaleString('en', { month: 'short' })}`;
  const s = SUBJ_BY_ID[subject] || SUBJ_BY_ID.maths;
  return `${s.short || s.name} — ${date}`;
}

// Recording page — real MediaRecorder + Supabase upload + lecture-process
function RecordingFullPage({ payload, onStop, goto }) {
  const [seconds, setSeconds] = nUseState(0);
  const [paused, setPaused] = nUseState(false);
  const [phase, setPhase] = nUseState('recording'); // 'recording' | 'uploading' | 'processing' | 'error'
  const [errorMsg, setErrorMsg] = nUseState('');
  const mediaRecorderRef = nUseRef(null);
  const chunksRef = nUseRef([]);
  const streamRef = nUseRef(null);

  nUseEffect(() => {
    startRecording();
    return () => stopStream();
  }, []);

  nUseEffect(() => {
    if (paused || phase !== 'recording') return;
    const t = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(t);
  }, [paused, phase]);

  async function startRecording() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      streamRef.current = stream;
      const mr = new MediaRecorder(stream, { mimeType: getSupportedMimeType() });
      mediaRecorderRef.current = mr;
      chunksRef.current = [];
      mr.ondataavailable = (e) => { if (e.data.size > 0) chunksRef.current.push(e.data); };
      mr.start(1000);
    } catch (e) {
      setPhase('error');
      setErrorMsg('Microphone access denied. Please allow microphone permissions.');
    }
  }

  function stopStream() {
    streamRef.current?.getTracks().forEach(t => t.stop());
  }

  function handlePause() {
    if (!mediaRecorderRef.current) return;
    if (paused) { mediaRecorderRef.current.resume(); setPaused(false); }
    else { mediaRecorderRef.current.pause(); setPaused(true); }
  }

  async function handleStop() {
    if (!mediaRecorderRef.current) { onStop(); return; }

    setPhase('uploading');
    stopStream();

    await new Promise(resolve => {
      mediaRecorderRef.current.onstop = resolve;
      mediaRecorderRef.current.stop();
    });

    const mimeType = getSupportedMimeType();
    const ext = mimeType.includes('ogg') ? 'ogg' : mimeType.includes('mp4') ? 'mp4' : 'webm';
    const blob = new Blob(chunksRef.current, { type: mimeType });
    const filename = `${Date.now()}-${payload.subject}.${ext}`;

    try {
      await storageUpload('recordings', filename, blob);
      setPhase('processing');

      const notePrefs = (() => { try { return JSON.parse(localStorage.getItem('lynxe-note-prefs') || '{}'); } catch { return {}; } })();

      const result = await fnPost('lecture-process', {
        subject:    payload.subject,
        audio_path: filename,
        title:      payload.title,
        pointers:   payload.pointers || '',
        notePrefs,
      });

      // Fire note-embed in background for paste text and file attachments
      const hasExtras = payload.pasteText?.trim() || payload.attachments?.length > 0;
      if (result?.session_id && hasExtras) {
        fnPost('note-embed', {
          session_id: result.session_id,
          subject:    payload.subject,
          title:      payload.title,
          text:       payload.pasteText || '',
          attachments: payload.attachments || [],
        }).catch(e => console.error('note-embed error:', e));
      }

      invalidateCache('lecture-sessions');
      onStop();
    } catch (e) {
      console.error('lecture-process error:', e);
      setPhase('error');
      setErrorMsg(e.message || 'Processing failed. Your recording was saved — you can retry later.');
    }
  }

  const fmt = (s) => `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`;

  if (phase === 'uploading' || phase === 'processing') {
    return (
      <>
        <Topbar crumbs={['Notes', 'Processing']} />
        <div className="content">
          <div className="rec-fullpage">
            <SubjectTag subject={payload.subject} />
            <div style={{ fontSize: 14, fontWeight: 500, textAlign: 'center', maxWidth: 480 }}>{payload.title}</div>
            <div className="rec-timer">{fmt(seconds)}</div>
            <div className="hstack dim" style={{ gap: 8, fontSize: 13 }}>
              <span className="spinner" />
              {phase === 'uploading' ? 'Uploading recording…' : 'Generating notes in Notion…'}
            </div>
            <div className="dim" style={{ fontSize: 12, textAlign: 'center', maxWidth: 360, marginTop: 4 }}>
              {phase === 'processing' ? 'Transcribing audio and writing study notes. This may take a few minutes.' : ''}
            </div>
          </div>
        </div>
      </>
    );
  }

  if (phase === 'error') {
    return (
      <>
        <Topbar crumbs={['Notes', 'Error']} />
        <div className="content">
          <div className="rec-fullpage">
            <div style={{ color: 'var(--danger)', fontSize: 14, textAlign: 'center', maxWidth: 400 }}>{errorMsg}</div>
            <button className="btn" onClick={onStop}>Back to Notes</button>
          </div>
        </div>
      </>
    );
  }

  return (
    <>
      <Topbar
        crumbs={['Notes', 'Recording']}
        actions={
          <span className="hstack" style={{ color: paused ? 'var(--warn)' : 'var(--danger)', fontSize: 11.5, fontWeight: 500 }}>
            {!paused && <span className="rec-dot" />}
            {paused ? 'PAUSED' : 'RECORDING'}
          </span>
        }
      />
      <div className="content">
        <div className="rec-fullpage">
          <SubjectTag subject={payload.subject} />
          <div style={{ fontSize: 14, fontWeight: 500, textAlign: 'center', maxWidth: 480 }}>{payload.title}</div>
          <div className="rec-timer">{fmt(seconds)}</div>
          {!paused && (
            <div className="rec-bars">
              {[...Array(24)].map((_, i) => (
                <span key={i} style={{ animationDelay: `${i * 0.05}s` }} />
              ))}
            </div>
          )}
          <div className="hstack" style={{ gap: 8 }}>
            <button className="btn lg" onClick={handlePause}>
              {paused ? <><I.Play size={11} /> Resume</> : <><I.Pause size={11} /> Pause</>}
            </button>
            <button className="btn lg danger" onClick={handleStop}>
              <I.Stop size={11} /> Stop & Process
            </button>
          </div>
          <div className="dim" style={{ fontSize: 11.5, textAlign: 'center', maxWidth: 360, marginTop: 4 }}>
            {payload.selectedPosts?.length > 0
              ? `${payload.selectedPosts.length} Classroom post${payload.selectedPosts.length === 1 ? '' : 's'} attached.`
              : 'AI note taker will draft to Notion when you stop.'}
          </div>
        </div>
      </div>
    </>
  );
}

function getSupportedMimeType() {
  const types = ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4'];
  return types.find(t => MediaRecorder.isTypeSupported(t)) || 'audio/webm';
}

window.Notes = Notes;
window.NewLecture = NewLecture;
window.RecordingFullPage = RecordingFullPage;
window.SubjectInline = SubjectInline;
window.openNotion = openNotion;
