/* Dump — clarify.jsx: the GTD Clarify stage.
   Processes inbox items one at a time after a brain offload.
   Two modes: 'cards' (default) and 'chat'.
   Each ambiguous item gets ONE question ("What do you need to do about [item]?"),
   with at most ONE follow-up. The classifier may return several tasks from a
   single answer (two errands → two next-actions) — all of them are committed. */

// "Sort out [noun]" items, or anything Claude flagged, need a question.
// Everything else auto-routes silently.
function needsClarify(task) {
  return task.clarify === true || !!task.clarifyKind || /^sort out /i.test(task.text);
}
function extractNoun(task) {
  return task.text.replace(/^sort out /i, '').trim();
}
function clarifyQuestion(noun) {
  return 'What do you need to do about ' + (noun.length < 20 ? 'the ' : '') + noun + '?';
}

// Bucket → label + icon (uses the app's SVG icon set, no emoji)
function bucketMeta(b) {
  const m = {
    'next-action':   { label: 'Next action', icon: Icons.bolt },
    'project':       { label: 'Project',      icon: Icons.tasks },
    'waiting-for':   { label: 'Waiting for',  icon: Icons.hourglass },
    'calendar':      { label: 'Calendar',     icon: Icons.calendar },
    'someday-maybe': { label: 'Someday',      icon: Icons.pause },
    'reference':     { label: 'Reference',    icon: Icons.file },
    'trash':         { label: 'Trash',        icon: Icons.trash }
  };
  return m[b] || m['next-action'];
}

function AiBadge() {
  return <span className="ai-badge">{Icons.sparkle(15)}</span>;
}

/* ---------- The Clarify queue ---------- */
function ClarifySection() {
  const state = useDumpStore();
  const { settings } = state;
  const mode = settings.clarifyMode || 'cards';

  // Snapshot the inbox once so committing items doesn't reshuffle the queue.
  const [queue] = useState(() => DumpStore.getState().tasks.filter((t) => t.bucket === 'inbox'));
  const [idx, setIdx] = useState(0);
  const routed = useRef(false);

  // Auto-route the high-confidence items silently on mount.
  useEffect(() => {
    if (routed.current) return;
    routed.current = true;
    queue.forEach((task) => {
      if (needsClarify(task)) return;
      DumpAPI.commitClarifiedItem(task.id, {
        title: task.text,
        bucket: task.gtdBucket || (task.big ? 'project' : 'next-action'),
        firstNextAction: null,
        minutes: task.minutes,
        contextTags: ['anywhere']
      });
    });
  }, []);

  const toAsk = queue.filter(needsClarify);
  const finished = idx >= toAsk.length;

  useEffect(() => {
    if (queue.length === 0) { DumpStore.set({ route: 'tasks' }); return; }
    if (finished) {
      // Safety sweep: anything from this queue still sitting in the inbox was
      // never answered (skipped card, race, navigation) — commit it to the board
      // tagged "Needs sorting" so it can never silently resurface in a later dump.
      var leaked = 0;
      queue.forEach((task) => {
        const cur = DumpStore.getState().tasks.find((t) => t.id === task.id);
        if (!cur || cur.bucket !== 'inbox') return;
        leaked++;
        DumpAPI.commitClarifiedItem(task.id, {
          title: cur.text, bucket: 'next-action', firstNextAction: null, minutes: cur.minutes, contextTags: ['anywhere']
        });
        DumpStore.set((s) => ({ tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, needsSorting: true } : t)) }));
      });
      DumpStore.set({ route: 'tasks', lastClarify: new Date().toISOString() });
      DumpAPI.toast('Done — ' + queue.length + ' item' + (queue.length === 1 ? '' : 's') + ' sorted.' + (leaked ? ' ' + leaked + ' tagged “Needs sorting”.' : ''));
    }
  }, [finished]);

  if (queue.length === 0 || finished) return null;

  const currentTask = toAsk[idx];

  return (
    <div className="section clarify-section" data-screen-label="Clarify">
      <div className="section-head">
        <h1 className="section-title">One quick question</h1>
      </div>
      <p className="section-sub">
        A couple of things need one quick question before they become real tasks.
      </p>

      <div className="clarify-stage">
        <ContextHint id="hint-clarify-first" icon={Icons.sparkle(16)}>
          A few items you offloaded need one quick question before they become real tasks. One at a time — under a minute.
        </ContextHint>
        <div className="clarify-progress">
          <span className="clarify-count">{idx + 1} of {toAsk.length} to clarify</span>
          <span className="clarify-dots">
            {toAsk.map((_, i) => (
              <span key={i} className={'cdot' + (i < idx ? ' done' : i === idx ? ' active' : '')}></span>
            ))}
          </span>
        </div>
        <div className="clarify-mode">
          <span className="clarify-mode-lbl">Answer by</span>
          <div className="seg seg-sm clarify-mode-seg">
            <button className={mode === 'cards' ? 'active' : ''}
              onClick={() => DumpStore.set((s) => ({ settings: { ...s.settings, clarifyMode: 'cards' } }))}>Tapping</button>
            <button className={mode === 'chat' ? 'active' : ''}
              onClick={() => DumpStore.set((s) => ({ settings: { ...s.settings, clarifyMode: 'chat' } }))}>Chatting</button>
          </div>
        </div>

        {mode === 'chat' && (!currentTask.clarifyKind || currentTask.clarifyKind === 'vague')
          ? <ClarifyChat key={currentTask.id} task={currentTask} onDone={() => setIdx((i) => i + 1)} />
          : <ClarifyCard key={currentTask.id} task={currentTask} onDone={() => setIdx((i) => i + 1)} />}
      </div>
    </div>
  );
}

/* ---------- Card mode ----------
   One card, four shapes of question:
   - vague : the classic "what do you need to do about X?" → AI reshapes it
   - child : "which child is this for?" → tap a child chip (tags siblings too)
   - date  : "when is this due?" → a date picker, no title rewrite
   - who   : "which company is this with?" → short text, appended to the title  */
function ClarifyCard({ task, onDone }) {
  const state = useDumpStore();
  const live = state.tasks.find((t) => t.id === task.id) || task;
  const kindRaw = live.clarifyKind && live.clarifyKind !== 'vague' ? live.clarifyKind : 'vague';
  // No children configured → a "which child?" chip card is a dead end; fall back
  // to the free-text "who" question instead.
  const children = state.settings.children || [];
  const kind = kindRaw === 'child' && children.length === 0 ? 'who' : kindRaw;
  const noun = extractNoun(task);

  const [answer, setAnswer] = useState('');
  const [dateVal, setDateVal] = useState(live.dueDate || '');
  const [busy, setBusy] = useState(false);
  const [leaving, setLeaving] = useState(false);
  const [followUp, setFollowUp] = useState(null);
  const [courseMode, setCourseMode] = useState(false);
  const [dailyDays, setDailyDays] = useState(10);
  const firstAnswer = useRef('');
  const inputRef = useRef(null);
  const dateRef = useRef(null);
  const skippedSibling = useRef(false);
  const advanced = useRef(false);

  // Guarded: a card may try to advance twice (its own commit ALSO fires the
  // sibling-skip effect below) — without this, answering one card skips the next.
  const advance = () => {
    if (advanced.current) return;
    advanced.current = true;
    setLeaving(true); setTimeout(onDone, 300);
  };

  // A sibling from the same letter answered this for us → slide past silently.
  useEffect(() => {
    if (!skippedSibling.current && !needsClarify(live)) { skippedSibling.current = true; advance(); }
  }, [live.clarifyKind, live.bucket, live.childId]);

  const focusInput = () => setTimeout(() => inputRef.current && inputRef.current.focus(), 80);
  useEffect(() => { if (kind === 'vague' || kind === 'who') { const t = focusInput(); return () => clearTimeout(t); } }, []);

  // -- vague: AI reshape (with one optional follow-up) --
  const confirmVague = async () => {
    if (busy || leaving) return;
    const ans = answer.trim();
    setBusy(true);
    try {
      const askingFollowUp = followUp === null;
      const combined = askingFollowUp ? ans : (firstAnswer.current + '. ' + ans);
      const res = await DumpAPI.clarifyItem(noun, combined, askingFollowUp);
      if (askingFollowUp && res && res.followUp) {
        firstAnswer.current = ans;
        setFollowUp(res.followUp);
        setAnswer('');
        setBusy(false);
        focusInput();
        return;
      }
      DumpAPI.commitClarifiedItem(task.id, res);
      advance();
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Couldn’t reach AI — skip this one or head to your board.', {
        action: { label: 'Go to board', fn: () => DumpStore.set({ route: 'tasks' }) }
      });
      setBusy(false);
    }
  };

  // -- child: tag this task + any siblings from the same source --
  const pickChild = (childId) => { if (busy || leaving) return; DumpAPI.assignChild(task.id, childId); advance(); };

  // -- date: set a due date in place, no rewrite --
  const confirmDate = () => {
    if (busy || leaving) return;
    // Read the input directly as a fallback — some browsers don't fire React's
    // onChange for <input type="date"> until blur, which left the button looking
    // "stuck" (greyed) right after picking a date.
    const v = (dateVal || (dateRef.current && dateRef.current.value) || '').trim();
    if (!v) { DumpAPI.toast('Pick a date first — or choose “No date needed”.'); return; }
    DumpAPI.resolveInboxTask(task.id, { dueDate: v, calendarType: live.time ? 'appointment' : 'day-action' });
    advance();
  };

  // -- daily: turn it into a tracked, every-day routine (lives on Today) --
  const confirmDaily = (days) => {
    if (busy || leaving) return;
    const rec = { frequency: 'daily', days: [0, 1, 2, 3, 4, 5, 6], endDate: null };
    if (days && days > 0) {
      rec.startDate = DumpUtil.todayISO();
      const end = new Date(); end.setHours(12, 0, 0, 0); end.setDate(end.getDate() + days - 1);
      rec.endDate = end.getFullYear() + '-' + String(end.getMonth() + 1).padStart(2, '0') + '-' + String(end.getDate()).padStart(2, '0');
    }
    DumpAPI.resolveInboxTask(task.id, { recurrence: rec, trackDaily: true, completions: [], dueDate: null, calendarType: null });
    DumpAPI.toast(days
      ? ('Tracking for ' + days + ' days — it’ll stop on its own.')
      : 'Tracking daily — find it under “Every day” on Today.');
    advance();
  };
  const declineDaily = () => {
    if (busy || leaving) return;
    DumpAPI.resolveInboxTask(task.id, {});
    advance();
  };

  // -- who: append the named party to the title --
  const confirmWho = () => {
    if (busy || leaving) return;
    const v = answer.trim();
    if (!v) { skip(); return; }
    // If the item is still an unclarified "Sort out …" placeholder, the answer is
    // the ACTION (not a person to append) — reshape it into a proper task instead
    // of producing "Sort out cat kibble (Order online)".
    if (/^sort\s+out\b/i.test(live.text || '')) { confirmVague(); return; }
    const base = live.text.replace(/\s*\([^)]*\)\s*$/, '');
    DumpAPI.resolveInboxTask(task.id, { text: base + ' (' + v + ')' });
    advance();
  };

  const skip = () => {
    if (busy || leaving) return;
    if (kind === 'daily') { DumpAPI.resolveInboxTask(task.id, {}); advance(); return; }
    if (kind === 'child') { DumpAPI.assignChild(task.id, null); advance(); return; }
    if (kind === 'date' || kind === 'who') {
      // Skipped with the info still missing → board, tagged, same as vague skips.
      DumpAPI.resolveInboxTask(task.id, {});
      DumpStore.set((s) => ({ tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, needsSorting: true } : t)) }));
      DumpAPI.toast('Skipped — on your board, tagged “Needs sorting”.');
      advance(); return;
    }
    DumpAPI.commitClarifiedItem(task.id, {
      title: task.text, bucket: 'next-action', firstNextAction: null, minutes: task.minutes, contextTags: ['anywhere']
    });
    DumpStore.set((s) => ({ tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, needsSorting: true } : t)) }));
    DumpAPI.toast('Skipped — on your board, tagged “Needs sorting”.');
    advance();
  };

  const rawLabel = kind === 'vague' ? noun : live.text;
  const question = kind === 'vague'
    ? (followUp || clarifyQuestion(noun))
    : (live.clarifyAsk || (kind === 'child' ? 'Which child is this for?' : kind === 'date' ? 'When is this due?' : 'Who is this with?'));

  return (
    <div className={'clarify-card' + (leaving ? ' leaving' : '')}>
      <div className="clarify-raw">Raw <span>&ldquo;{rawLabel}&rdquo;</span></div>

      {kind === 'vague' && followUp ? (
        <p className="clarify-firstanswer">You said: &ldquo;{firstAnswer.current}&rdquo;</p>
      ) : null}

      <div className="clarify-q">
        <AiBadge />
        <p>{question}</p>
      </div>

      {kind === 'child' ? (
        <React.Fragment>
          {children.length ? (
            <div className="clarify-chips">
              {children.map((c) => (
                <button key={c.id} className="clarify-chip" onClick={() => pickChild(c.id)}>
                  {c.name}{c.label ? <span className="cc-class">{c.label}</span> : null}
                </button>
              ))}
              <button className="clarify-chip ghost" onClick={() => pickChild(null)}>Not sure / all of them</button>
            </div>
          ) : (
            <p className="clarify-firstanswer">No children added yet — add them in Settings to tag tasks by child.</p>
          )}
          <div className="clarify-actions">
            <button className="btn btn-ghost" onClick={skip}>Skip for now</button>
          </div>
        </React.Fragment>
      ) : kind === 'daily' ? (
        <React.Fragment>
          <div className="clarify-daily-actions">
            <button className="btn btn-primary" onClick={() => confirmDaily(null)}>{Icons.repeat(15)} Yes — every day</button>
            <button className={'btn btn-ghost' + (courseMode ? ' active' : '')} onClick={() => setCourseMode((o) => !o)}>{Icons.calendar(15)} Just for a while…</button>
            <button className="btn btn-ghost" onClick={declineDaily}>No — just once</button>
          </div>
          {courseMode ? (
            <div className="clarify-course">
              <span>Track for</span>
              <input type="number" min="1" max="365" value={dailyDays}
                onChange={(e) => setDailyDays(e.target.value)}
                onKeyDown={(e) => { if (e.key === 'Enter') confirmDaily(parseInt(dailyDays, 10) || 10); }} />
              <span>days, then stop</span>
              <button className="btn btn-primary btn-sm" onClick={() => confirmDaily(parseInt(dailyDays, 10) || 10)}>Start →</button>
            </div>
          ) : null}
          <p className="clarify-daily-note">Daily things live on Today with a tick each day — you’ll see your streak and any missed days. A memory aid, not an alarm.</p>
        </React.Fragment>
      ) : kind === 'date' ? (
        <React.Fragment>
          <div className="clarify-daterow">
            <input type="date" ref={dateRef} className="clarify-date" value={dateVal}
              onChange={(e) => setDateVal(e.target.value)} onInput={(e) => setDateVal(e.target.value)} />
            <button className="btn btn-primary" onClick={confirmDate}>Set date →</button>
          </div>
          <div className="clarify-actions">
            <button className="btn btn-ghost" onClick={() => { DumpAPI.resolveInboxTask(task.id, {}); advance(); }}>No date needed</button>
          </div>
        </React.Fragment>
      ) : (
        <React.Fragment>
          <textarea
            ref={inputRef}
            className="clarify-input"
            rows={2}
            placeholder={kind === 'who' ? 'e.g. the name of the company or person' : (followUp ? 'A few more words…' : 'e.g. take to vet for annual shots')}
            value={answer}
            disabled={busy}
            onChange={(e) => setAnswer(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); kind === 'who' ? confirmWho() : confirmVague(); } }}
          ></textarea>
          <div className="clarify-actions">
            <button className="btn btn-ghost" onClick={skip} disabled={busy}>Skip for now</button>
            <button className="btn btn-primary" onClick={kind === 'who' ? confirmWho : confirmVague} disabled={busy}>
              {busy ? <span className="spinner"></span> : null}
              {busy ? 'Sorting…' : 'Done →'}
            </button>
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

/* ---------- Chat mode ---------- */
function ClarifyChat({ task, onDone }) {
  const noun = extractNoun(task);
  const [phase, setPhase] = useState('asking'); // asking | thinking | result
  const [draft, setDraft] = useState('');
  const [a1, setA1] = useState(null);       // first answer (shown as user bubble)
  const [followUpQ, setFollowUpQ] = useState(null);
  const [a2, setA2] = useState(null);       // follow-up answer
  const [tasks, setTasks] = useState(null); // array of result task objects
  const [editing, setEditing] = useState(false);
  const [editTitle, setEditTitle] = useState('');
  const [leaving, setLeaving] = useState(false);
  const inputRef = useRef(null);

  const focusInput = () => setTimeout(() => inputRef.current && inputRef.current.focus(), 80);
  useEffect(() => { const t = focusInput(); return () => clearTimeout(t); }, []);

  const advance = () => { setLeaving(true); setTimeout(onDone, 300); };
  const commit = (list) => { DumpAPI.commitClarifiedItem(task.id, { tasks: list }); advance(); };

  const send = async () => {
    if (phase !== 'asking') return;
    const ans = draft.trim();
    const askingFollowUp = followUpQ === null;
    setPhase('thinking');
    if (askingFollowUp) setA1(ans); else setA2(ans);
    setDraft('');
    try {
      const combined = askingFollowUp ? ans : (a1 + '. ' + ans);
      const res = await DumpAPI.clarifyItem(noun, combined, askingFollowUp);
      if (askingFollowUp && res && res.followUp) {
        setFollowUpQ(res.followUp);
        setPhase('asking');
        focusInput();
        return;
      }
      const list = res.tasks || [];
      setTasks(list);
      setEditTitle(list[0] ? list[0].title : '');
      setPhase('result'); // wait for the user to confirm — no auto-advance
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Something went wrong — try again.');
      setPhase('asking');
    }
  };

  const startEdit = () => { setEditing(true); };
  const saveEdit = () => {
    const list = tasks.slice();
    list[0] = Object.assign({}, list[0], { title: editTitle.trim() || list[0].title });
    commit(list);
  };
  const looksGood = () => commit(tasks);

  const single = tasks && tasks.length === 1;

  return (
    <div className={'clarify-chat' + (leaving ? ' leaving' : '')}>
      <div className="chat-thread">
        <div className="chat-msg ai">
          <AiBadge />
          <div className="bubble">{clarifyQuestion(noun)}</div>
        </div>

        {a1 !== null ? (
          <div className="chat-msg user"><div className="bubble">{a1 || '(no detail)'}</div></div>
        ) : null}

        {followUpQ ? (
          <div className="chat-msg ai"><AiBadge /><div className="bubble">{followUpQ}</div></div>
        ) : null}

        {a2 !== null ? (
          <div className="chat-msg user"><div className="bubble">{a2 || '(no detail)'}</div></div>
        ) : null}

        {phase === 'thinking' ? (
          <div className="chat-msg ai">
            <AiBadge />
            <div className="bubble typing"><span></span><span></span><span></span></div>
          </div>
        ) : null}

        {phase === 'result' && tasks ? (
          <div className="chat-msg ai">
            <AiBadge />
            <div className="bubble result">
              {tasks.map((t, i) => {
                const meta = bucketMeta(t.bucket);
                return (
                  <div key={i} className="result-item">
                    <span className="bucket-tag">{meta.icon(12)} {meta.label}</span>
                    {single && editing ? (
                      <input
                        className="chat-edit"
                        value={editTitle}
                        autoFocus={true}
                        onChange={(e) => setEditTitle(e.target.value)}
                        onKeyDown={(e) => { if (e.key === 'Enter') saveEdit(); }}
                      ></input>
                    ) : (
                      <p className="result-title">{t.title}</p>
                    )}
                    {t.bucket === 'project' && t.firstNextAction
                      ? <p className="result-next">First step: {t.firstNextAction}</p>
                      : null}
                  </div>
                );
              })}
              <div className="chat-result-actions">
                {single && editing ? (
                  <button className="btn btn-primary btn-sm" onClick={saveEdit}>Save</button>
                ) : (
                  <React.Fragment>
                    {single ? <button className="btn btn-ghost btn-sm" onClick={startEdit}>Edit</button> : null}
                    <button className="btn btn-primary btn-sm" onClick={looksGood}>
                      {single ? 'Looks good' : 'Add all ' + tasks.length}
                    </button>
                  </React.Fragment>
                )}
              </div>
            </div>
          </div>
        ) : null}
      </div>

      {phase === 'asking' ? (
        <div className="chat-compose">
          <textarea
            ref={inputRef}
            rows={1}
            placeholder={followUpQ ? 'A few more words…' : 'Type a short answer…'}
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }}
          ></textarea>
          <button className="btn btn-primary" onClick={send}>Send</button>
        </div>
      ) : null}
    </div>
  );
}

window.ClarifySection = ClarifySection;
