/* Dump — capture.jsx: the brain offload section */

function CaptureSection() {
  const state = useDumpStore();
  const { settings, lastDump } = state;
  const [quickMode, setQuickMode] = useState(false);
  const [text, setText] = useState('');
  const [quick, setQuick] = useState({ weighing: '', urgent: '', kids: '' });
  const [busy, setBusy] = useState(false);
  const [nudgeDismissed, setNudgeDismissed] = useState(false);
  const [fileDialogOpen, setFileDialogOpen] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const [fileBusy, setFileBusy] = useState(false);
  const [pendingSource, setPendingSource] = useState(null);
  const [listPrompt, setListPrompt] = useState(null);
  const taRef = useRef(null);
  const capFileRef = useRef(null);

  const addFileToBox = async (files) => {
    const file = files && files[0];
    if (!file) return;
    setFileBusy(true);
    try {
      const name = file.name.toLowerCase();
      const append = (txt) => {
        if (quickMode) setQuickMode(false);
        setText((cur) => (cur.trim() ? cur.replace(/\s*$/, '\n\n') : '') + txt.trim());
        const isLetterish = name.endsWith('.pdf') || file.type.startsWith('image/');
        setPendingSource({ kind: isLetterish ? 'letter' : 'file', label: file.name.replace(/\.[^.]+$/, '') });
        setFileDialogOpen(false);
        DumpAPI.toast('Added “' + file.name + '” to your dump.');
        setTimeout(() => taRef.current && taRef.current.focus(), 60);
      };
      if (name.endsWith('.txt') || name.endsWith('.md') || file.type.startsWith('text/')) {
        const t = await file.text();
        append(t.slice(0, 20000));
      } else if (DumpAPI.aiOn() && (name.endsWith('.pdf') || file.type.startsWith('image/'))) {
        const b64 = await new Promise((res, rej) => {
          const r = new FileReader();
          r.onload = () => res(String(r.result).split(',')[1]);
          r.onerror = rej;
          r.readAsDataURL(file);
        });
        const block = file.type.startsWith('image/')
          ? { type: 'image', source: { type: 'base64', media_type: file.type, data: b64 } }
          : { type: 'document', source: { type: 'base64', media_type: 'application/pdf', data: b64 } };
        const reply = await DumpAPI.runAI(
          'transcribe', {},
          [block, { type: 'text', text: 'Transcribe the text content of this file.' }], 1500);
        append(String(reply || '').trim() || '(' + file.name + ' had no readable text)');
      } else {
        DumpAPI.toast("Can't read that format yet — try a .txt, .md, PDF or image.");
      }
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : "Couldn't read that file — try another format.");
    } finally {
      setFileBusy(false);
      if (capFileRef.current) capFileRef.current.value = '';
    }
  };

  const CHIPS = [
    { label: 'Bad morning — just 3 things', seed: 'Bad morning. The three things on my mind: ' },
    { label: 'Work stuff', seed: 'Work stuff: ' },
    { label: 'Kids / school', seed: 'Kids and school stuff: ' },
    { label: "What's urgent?", seed: 'Urgent today: ' },
    { label: "What have I been avoiding?", seed: "Things I've been avoiding: " }
  ];

  // Auto-grow
  const autoGrow = (el) => {
    if (!el) return;
    el.style.height = 'auto';
    el.style.height = Math.max(150, el.scrollHeight) + 'px';
  };
  useEffect(() => { if (!quickMode) autoGrow(taRef.current); }, [text, quickMode]);

  // Expose focus hook for keyboard shortcut
  useEffect(() => {
    window.__focusDump = () => {
      setQuickMode(false);
      setTimeout(() => taRef.current && taRef.current.focus(), 60);
    };
    return () => { delete window.__focusDump; };
  }, []);

  const fillChip = (seed) => {
    if (quickMode) setQuickMode(false);
    setText((t) => (t.trim() ? t.replace(/\s*$/, '\n') + seed : seed));
    setTimeout(() => {
      const el = taRef.current;
      if (el) { el.focus(); el.selectionStart = el.selectionEnd = el.value.length; }
    }, 50);
  };

  const combined = quickMode
    ? [
        quick.weighing && "What's weighing on me: " + quick.weighing,
        quick.urgent && 'Urgent today: ' + quick.urgent,
        quick.kids && 'Kids / family: ' + quick.kids
      ].filter(Boolean).join('\n')
    : text;

  const sort = async () => {
    const raw = combined.trim();
    if (!raw) { DumpAPI.toast('Nothing to sort yet — offload something first.'); return; }
    // A shopping-list-shaped dump gets ONE question first: list, or tasks?
    const listItems = DumpAPI.detectShoppingList(raw);
    if (listItems && !listPrompt) {
      // Pre-select recognised groceries; leave the odd ones out unchecked. The user
      // can click any chip to include/exclude it before committing.
      setListPrompt({ raw, items: listItems, sel: listItems.map((it) => DumpAPI.groceryCat(it) !== 'Other') });
      return;
    }
    await runSort(raw);
  };

  const toggleListItem = (i) => {
    setListPrompt((lp) => {
      if (!lp) return lp;
      const sel = lp.sel.slice();
      sel[i] = !sel[i];
      return { ...lp, sel };
    });
  };

  const runSort = async (raw) => {
    setListPrompt(null);
    setBusy(true);
    try {
      const n = await DumpAPI.processDump(raw, pendingSource);
      setText('');
      setQuick({ weighing: '', urgent: '', kids: '' });
      setPendingSource(null);
      DumpAPI.toast(
        n === 0 ? 'Nothing new found — it may all be on your list already.'
        : n === 1 ? '1 task added' : n + ' tasks added'
      );
      if (n > 0) DumpStore.set({ route: 'clarify' });
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Something went wrong — try again.',
        e.parse ? { retry: () => { runSort(raw); } } : undefined);
    } finally {
      setBusy(false);
    }
  };

  const keepAsList = async () => {
    if (!listPrompt) return;
    // Respect the user's selection, not just the classifier: checked → list, unchecked → tasks.
    const groceryItems = listPrompt.items.filter((t, i) => listPrompt.sel[i]);
    const otherItems = listPrompt.items.filter((t, i) => !listPrompt.sel[i]);
    setListPrompt(null);
    setText('');
    setQuick({ weighing: '', urgent: '', kids: '' });
    const src = pendingSource;
    setPendingSource(null);

    const added = groceryItems.length ? DumpAPI.addGroceries(groceryItems) : 0;
    // Anything the user left unchecked goes through normal task sorting.
    let taskCount = 0;
    if (otherItems.length) {
      try { taskCount = await DumpAPI.processDump(otherItems.join('\n'), src); } catch (e) {}
    }

    const parts = [];
    if (added > 0) parts.push(added === 1 ? '1 item added to Groceries' : added + ' items added to Groceries');
    else if (groceryItems.length) parts.push('Those are already on your Groceries list');
    if (taskCount > 0) parts.push(taskCount === 1 ? '1 saved as a task' : taskCount + ' saved as tasks');

    DumpAPI.toast(
      parts.join(' · ') || 'Nothing new to add.',
      added > 0 ? { action: { label: 'View list', fn: () => DumpStore.set({ route: 'groceries' }) } } : undefined
    );
    // Non-grocery items need clarifying (a bare "gardener" is vague) — send them there.
    if (taskCount > 0) DumpStore.set({ route: 'clarify' });
  };

  const clearAll = () => {
    const prevText = text;
    const prevQuick = quick;
    const prevSource = pendingSource;
    if (!(prevText.trim() || prevQuick.weighing || prevQuick.urgent || prevQuick.kids)) return;
    setText('');
    setQuick({ weighing: '', urgent: '', kids: '' });
    setPendingSource(null);
    DumpAPI.toast('Cleared.', { action: { label: 'Undo', fn: () => { setText(prevText); setQuick(prevQuick); setPendingSource(prevSource); } } });
    if (taRef.current) taRef.current.focus();
  };

  const days = DumpUtil.daysSince(lastDump);
  const showNudge = settings.habitReminder && !nudgeDismissed &&
    lastDump && days >= (settings.habitDays || 2);

  return (
    <div className="section" data-screen-label="Capture">
      <div className="section-head">
        <h1 className="section-title">Capture</h1>
        <span className="mode-toggle" onClick={() => setQuickMode(!quickMode)} role="switch" aria-checked={quickMode}>
          Quick mode
          <span className={'switch' + (quickMode ? ' on' : '')}></span>
        </span>
      </div>
      <p className="section-sub">Get it out of your head. Sorting is the app's job, not yours.</p>

      {showNudge ? (
        <Banner onClose={() => setNudgeDismissed(true)}>
          You haven't offloaded in {days} day{days === 1 ? '' : 's'}. Head empty or just busy? Either way — this helps.
        </Banner>
      ) : null}

      {quickMode ? (
        <div>
          {[
            { key: 'weighing', label: "What's weighing on you?" },
            { key: 'urgent', label: 'Anything urgent today?' },
            { key: 'kids', label: 'Anything for the kids / family?' }
          ].map((f) => (
            <div className="quick-field" key={f.key}>
              <label className="quick-label" htmlFor={'qf-' + f.key}>{f.label}</label>
              <textarea
                id={'qf-' + f.key}
                className="dump-box"
                readOnly={busy}
                value={quick[f.key]}
                onChange={(e) => setQuick({ ...quick, [f.key]: e.target.value })}
                onInput={(e) => autoGrow(e.target)}
              ></textarea>
            </div>
          ))}
          {(quick.weighing || quick.urgent || quick.kids) ? (
            <button type="button" className="dump-clear quick-clear" onClick={clearAll} disabled={busy}>Clear all</button>
          ) : null}
        </div>
      ) : (
        <div className="dump-wrap">
          <textarea
            ref={taRef}
            className="dump-box"
            placeholder="What's on your mind? Don't edit — just offload it all."
            readOnly={busy}
            value={text}
            onChange={(e) => setText(e.target.value)}
          ></textarea>
          <div className="dump-tools">
            <span className="cap-tool">
              <button type="button" className="cap-tool-btn" aria-label="Add a file"
                onClick={() => setFileDialogOpen(true)} disabled={busy}>
                {Icons.paperclip(19)}
              </button>
              <span className="cap-tip">Attach a file — a newsletter, notes or a scanned letter — and we'll pull its text into your dump. Accepts PDF, TXT, MD or images (PNG, JPG).</span>
            </span>
            <span className="cap-tool">
              <button type="button" className="cap-tool-btn cap-tool-soon" aria-label="Dictate — coming soon" aria-disabled="true" disabled>
                {Icons.mic(19)}
                <span className="cap-soon-badge">soon</span>
              </button>
              <span className="cap-tip">Dictate your thoughts out loud — coming soon.</span>
            </span>
            {text.trim() ? (
              <button type="button" className="dump-clear" onClick={clearAll} disabled={busy}>Clear</button>
            ) : null}
          </div>
        </div>
      )}

      {fileDialogOpen ? (
        <div className="cap-modal-backdrop" onClick={() => setFileDialogOpen(false)}>
          <div className="cap-modal" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="Add a file">
            <div className="cap-modal-head">
              <h3>Add a file</h3>
              <button type="button" className="cap-modal-close" aria-label="Close" onClick={() => setFileDialogOpen(false)}>×</button>
            </div>
            <p className="cap-modal-sub">School newsletters, meeting notes, scanned letters — drop one in and we'll pull the text straight into your dump.</p>
            <div
              className={'dropzone' + (dragOver ? ' over' : '')}
              onClick={() => capFileRef.current && capFileRef.current.click()}
              onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
              onDragLeave={() => setDragOver(false)}
              onDrop={(e) => { e.preventDefault(); setDragOver(false); addFileToBox(e.dataTransfer.files); }}
            >
              {fileBusy ? 'Reading…' : 'Drop a PDF, TXT or image here — or tap to choose'}
            </div>
            <input ref={capFileRef} type="file" accept=".pdf,.txt,.md,image/*" style={{ display: 'none' }}
              onChange={(e) => addFileToBox(e.target.files)} />
          </div>
        </div>
      ) : null}

      <div className="chip-row">
        {CHIPS.map((c) => (
          <button className="chip" key={c.label} onClick={() => fillChip(c.seed)}>{c.label}</button>
        ))}
      </div>

      {listPrompt ? (() => {
        const excluded = listPrompt.items.filter((it, i) => !listPrompt.sel[i]);
        const inList = listPrompt.sel.filter(Boolean).length;
        return (
        <div className="list-prompt" role="dialog" aria-label="Looks like a shopping list">
          <div className="list-prompt-head">
            {Icons.cart(18)}
            <span>Looks like a shopping list — {listPrompt.items.length} items.</span>
          </div>
          <p className="list-prompt-sub">Tap any item to include or exclude it. Checked items go on your Groceries list; the rest become tasks.</p>
          <div className="list-prompt-preview">
            {listPrompt.items.map((it, i) => (
              <button
                type="button"
                className={'list-prompt-chip toggle' + (listPrompt.sel[i] ? ' on' : ' off')}
                key={i}
                onClick={() => toggleListItem(i)}
                aria-pressed={listPrompt.sel[i]}
              >
                <span className="lpc-tick">{listPrompt.sel[i] ? Icons.check(12) : null}</span>
                {it}
              </button>
            ))}
          </div>
          {excluded.length ? (
            <p className="list-prompt-note">
              {excluded.join(', ')} {excluded.length === 1 ? "will become a task instead." : "will become tasks instead."}
            </p>
          ) : null}
          <div className="list-prompt-actions">
            <button className="btn btn-primary" onClick={keepAsList} disabled={inList === 0 && excluded.length === 0}>
              {inList === 0 ? 'Make them all tasks' : excluded.length === 0 ? 'Keep as a list' : 'Keep ' + inList + ' on list · ' + excluded.length + ' to tasks'}
            </button>
            <button className="btn btn-ghost" onClick={() => runSort(listPrompt.raw)}>Make them tasks</button>
          </div>
        </div>
        );
      })() : (
        <div className="capture-actions">
          <button className="btn btn-primary" onClick={sort} disabled={busy}>
            {busy ? <span className="spinner"></span> : null}
            {busy ? 'Sorting…' : 'Sort it out →'}
          </button>
        </div>
      )}
    </div>
  );
}

window.CaptureSection = CaptureSection;
