// ==========================================================================
// Views: ThreadView (chat + canvas of artifacts), AgentsView (scheduled).
// Each view is a real functional component driven by the store.
// ==========================================================================

// ---- Render a single artifact (type-dispatched) ----
function Artifact({ artifact }) {
  const { regenerateVariant, setToast } = useStore();
  const [selectedVariant, setSelectedVariant] = React.useState(null);

  switch (artifact.kind) {
    case 'parsed-files':
      return (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 12, marginBottom: 14 }}>
            {artifact.files.map(f => <FileCard key={f.id} file={f} />)}
          </div>
          <ContextCard files={artifact.files} />
        </>
      );
    case 'brief':
      return <BriefCard brief={artifact.brief} critique={artifact.critique} onOpen={() => setToast({ kind:'ok', text:'Opened in Inku production.' })} />;
    case 'pillars':
      return <MessagingArchitecture pillars={artifact.pillars} onOpen={() => setToast({ kind:'ok', text:'Opened pillars.' })} />;
    case 'concepts':
      return <AdConceptGrid concepts={artifact.concepts} onOpen={() => setToast({ kind:'ok', text:'Opened concept set.' })} />;
    case 'calendar':
      return <ContentCalendar onOpen={() => setToast({ kind:'ok', text:'Opened calendar.' })} />;
    case 'variant-matrix':
      return (
        <>
          <VariantMatrix variants={artifact.variants} onOpen={(v) => setSelectedVariant(v)} />
          {selectedVariant && (
            <VariantDetail
              variant={selectedVariant}
              onClose={() => setSelectedVariant(null)}
              onRegenerate={(instructions) => regenerateVariant(selectedVariant.id, instructions)}
            />
          )}
        </>
      );
    case 'perf-hypothesis':
      return <PerfHypothesis lift={artifact.lift} because={artifact.because} />;
    case 'agent-created':
      return (
        <CardShell kind="agent scheduled" title={artifact.agent.title}>
          <div style={{ fontSize: 13, color: 'var(--ink-soft)' }}>
            {artifact.agent.cadence}. First run queued — results will surface in the Scheduled Agents panel.
          </div>
        </CardShell>
      );
    default:
      return null;
  }
}

function VariantDetail({ variant, onClose, onRegenerate }) {
  const [instructions, setInstructions] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  return (
    <CardShell kind="variant detail" title={`${variant.persona} · ${variant.channel}`}
      actions={<button className="btn-reset" onClick={onClose} style={{ padding: 5, color: 'var(--ink-mute)', cursor: 'pointer' }}><Icon name="x" size={13} /></button>}>
      <div style={{ display: 'flex', gap: 16 }}>
        <div style={{ width: 180, aspectRatio: '1 / 1.3', background: variant.bg, color: variant.accent, borderRadius: 10, padding: 14, display: 'flex', flexDirection: 'column', justifyContent: 'space-between', position: 'relative', overflow: 'hidden', flexShrink: 0 }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '.14em', opacity: 0.7 }}>BRAME</div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 16, lineHeight: 1.1, fontWeight: 300, letterSpacing: '-0.015em' }}>{variant.copy}</div>
        </div>
        <div style={{ flex: 1 }}>
          <div className="label label-moss" style={{ marginBottom: 6 }}>Hook · {variant.hook}</div>
          <div style={{ fontFamily: 'var(--font-serif)', fontSize: 17, color: 'var(--ink)', marginBottom: 14 }}>"{variant.copy}"</div>
          <div className="label" style={{ marginBottom: 4 }}>Refine</div>
          <textarea value={instructions} onChange={(e) => setInstructions(e.target.value)}
            placeholder="Make it snappier. Swap 'sharper' for 'louder'. Localize for NL."
            style={{ width: '100%', minHeight: 60, padding: 10, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg)', fontFamily: 'var(--font-serif)', fontSize: 13, color: 'var(--ink)', resize: 'vertical' }} />
          <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
            <button className="btn-reset" disabled={busy} onClick={async () => { setBusy(true); await onRegenerate(instructions); setBusy(false); onClose(); }}
              style={{ padding: '8px 14px', borderRadius: 8, background: 'var(--moss-deep)', color: 'var(--bg)', fontSize: 12, cursor: busy ? 'default' : 'pointer', opacity: busy ? .7 : 1 }}>
              {busy ? 'Regenerating…' : 'Regenerate with tweaks'}
            </button>
            <button className="btn-reset" style={{ padding: '8px 14px', borderRadius: 8, border: '1px solid var(--line)', color: 'var(--ink-soft)', fontSize: 12, cursor: 'pointer' }}>
              Send to production
            </button>
          </div>
        </div>
      </div>
    </CardShell>
  );
}

// ---- Retrieval receipt card (consulting-brand / consulting-data) ----
// Rendered inline in the chat column — these are "reasoning beats", not canvas artifacts.
function ReceiptCard({ receipt }) {
  const isBrand = receipt.kind === 'brand-receipts';
  const label = isBrand ? 'Consulting brand' : 'Consulting data';
  const [open, setOpen] = React.useState(false);
  const summary = isBrand
    ? `${receipt.docs.length} source${receipt.docs.length === 1 ? '' : 's'}${receipt.guardrails && receipt.guardrails.length ? ` · ${receipt.guardrails.length} guardrails` : ''}`
    : `${receipt.metrics.length} metric${receipt.metrics.length === 1 ? '' : 's'}${receipt.priorTests && receipt.priorTests.length ? ` · prior test` : ''}`;
  return (
    <div style={{
      border: '1px solid var(--line)',
      background: 'var(--card-solid)',
      borderRadius: 10,
      marginTop: 10,
      fontSize: 12,
      overflow: 'hidden',
      transition: 'background .15s',
    }}>
      <button
        className="btn-reset"
        onClick={() => setOpen(v => !v)}
        aria-expanded={open}
        style={{
          width: '100%',
          display: 'flex',
          alignItems: 'center',
          gap: 8,
          padding: '9px 12px',
          cursor: 'pointer',
          textAlign: 'left',
          background: 'transparent',
        }}
        onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-2)'; }}
        onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; }}
      >
        <span style={{ fontSize: 9, color: isBrand ? 'var(--accent-warm-2)' : 'var(--moss-deep)' }}>◆</span>
        <span className="label" style={{ color: 'var(--ink-soft)' }}>Retrieved via {label}</span>
        <span style={{ flex: 1 }} />
        {!open && (
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--ink-mute)', letterSpacing: '.04em' }}>
            {summary}
          </span>
        )}
        <span aria-hidden="true" style={{
          fontSize: 10, color: 'var(--ink-mute)',
          transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
          transition: 'transform .18s cubic-bezier(.2,.7,.2,1)',
          display: 'inline-block',
          width: 12, textAlign: 'center',
        }}>▸</span>
      </button>
      {open && (
        <div className="fade-in" style={{ padding: '2px 12px 12px 12px' }}>
      {isBrand ? (
        <>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {receipt.docs.map((d, i) => (
              <div key={i} style={{ display: 'grid', gridTemplateColumns: '150px 1fr', gap: 10, fontSize: 11.5, lineHeight: 1.45 }}>
                <div style={{ color: 'var(--ink-soft)', fontFamily: 'var(--font-mono)', fontSize: 10, paddingTop: 1 }}>
                  {d.title}<br/>
                  <span style={{ color: 'var(--ink-mute)' }}>§ {d.page}</span>
                </div>
                <div style={{ color: 'var(--ink)', fontFamily: 'var(--font-serif)', fontStyle: 'italic' }}>
                  {d.snippet}
                </div>
              </div>
            ))}
          </div>
          {receipt.guardrails && receipt.guardrails.length > 0 && (
            <div style={{ marginTop: 10, paddingTop: 8, borderTop: '1px dashed var(--line)', display: 'flex', flexWrap: 'wrap', gap: 5 }}>
              <span className="label" style={{ color: 'var(--ink-mute)', marginRight: 4 }}>Guardrails</span>
              {receipt.guardrails.map((g, i) => (
                <span key={i} style={{ fontSize: 10, padding: '2px 8px', borderRadius: 99, background: 'var(--moss-glow)', color: 'var(--moss-deep)', fontFamily: 'var(--font-mono)' }}>
                  {g}
                </span>
              ))}
            </div>
          )}
        </>
      ) : (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '6px 20px' }}>
            {receipt.metrics.map((m, i) => (
              <div key={i} style={{ display: 'flex', flexDirection: 'column', gap: 2, borderBottom: '1px dashed var(--line)', paddingBottom: 5 }}>
                <span style={{ fontSize: 9.5, color: 'var(--ink-mute)', fontFamily: 'var(--font-mono)', letterSpacing: '.06em' }}>{m.label.toUpperCase()}</span>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                  <span style={{ fontSize: 14, color: 'var(--ink)', fontVariantNumeric: 'tabular-nums', fontFamily: 'var(--font-serif)' }}>{m.value}</span>
                  <span style={{ color: 'var(--ink-soft)', fontSize: 10 }}>{m.delta}</span>
                </div>
              </div>
            ))}
          </div>
          {receipt.priorTests && receipt.priorTests.length > 0 && (
            <div style={{ marginTop: 10, paddingTop: 8, borderTop: '1px dashed var(--line)', fontSize: 11, color: 'var(--ink-soft)' }}>
              <span className="label" style={{ color: 'var(--ink-mute)', marginRight: 4 }}>Prior test</span>
              {receipt.priorTests[0].when} — <b style={{ color: 'var(--ink)' }}>{receipt.priorTests[0].winner}</b> won by {receipt.priorTests[0].lift}
            </div>
          )}
        </>
      )}
        </div>
      )}
    </div>
  );
}

// ---- Clarifier card (inline structured form in chat) ----
function ClarifierCard({ clarifier, originalText, onSubmit, done, selectedAnswers }) {
  // When the form becomes "done", prefer the persisted selected answers over
  // any local state so the card reflects what the user actually submitted.
  const [answers, setAnswers] = React.useState(selectedAnswers || {});
  React.useEffect(() => {
    if (done && selectedAnswers) setAnswers(selectedAnswers);
  }, [done, selectedAnswers]);
  const [busy, setBusy] = React.useState(false);
  // Defensive: tolerate older persisted clarifiers that used `questions` instead
  // of `fields`, or had no fields at all. Never crash the app on a stale shape.
  const fields = Array.isArray(clarifier?.fields)
    ? clarifier.fields
    : Array.isArray(clarifier?.questions)
      ? clarifier.questions.map((q, i) => ({
          id: q?.id || `q_${i}`,
          label: q?.label || q?.question || q?.text || '',
          options: Array.isArray(q?.options) ? q.options : [],
        }))
      : [];
  if (fields.length === 0) {
    return (
      <div style={{
        border: '1px solid var(--line)', background: 'var(--bg)',
        borderRadius: 12, padding: '14px 16px', marginTop: 10,
        fontSize: 12, color: 'var(--ink-mute)', fontFamily: 'var(--font-mono)',
      }}>
        Clarifier could not be rendered (no fields).
      </div>
    );
  }
  const complete = fields.every(f => answers[f.id]);

  const submit = async () => {
    if (!complete || busy || done) return;
    setBusy(true);
    await onSubmit(answers, originalText);
  };

  return (
    <div style={{
      border: '1px solid var(--line)',
      background: 'var(--bg)',
      borderRadius: 12,
      padding: '14px 16px',
      marginTop: 10,
      boxShadow: '0 1px 0 rgba(0,0,0,.02)',
      opacity: done ? 0.72 : 1,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
        <span className="label label-moss">Before we commit</span>
        {done && <span style={{ fontSize: 10, color: 'var(--ink-mute)', fontFamily: 'var(--font-mono)' }}>· answered</span>}
      </div>
      {(clarifier?.preamble || clarifier?.intro) && (
        <div style={{ fontFamily: 'var(--font-serif)', fontSize: 14, lineHeight: 1.5, color: 'var(--ink)', marginBottom: 14 }}>
          {clarifier.preamble || clarifier.intro}
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {fields.map(f => {
          // Once done, only render the selected pill — cleaner than disabled row.
          const visibleOpts = done && answers[f.id] ? [answers[f.id]] : f.options;
          return (
            <div key={f.id}>
              <div className="label" style={{ color: 'var(--ink-soft)', marginBottom: 6 }}>{f.label}</div>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                {visibleOpts.map(opt => {
                  const active = answers[f.id] === opt;
                  return (
                    <button
                      key={opt}
                      type="button"
                      disabled={done}
                      className="btn-reset"
                      onClick={() => !done && setAnswers(a => ({ ...a, [f.id]: opt }))}
                      style={{
                        padding: '6px 11px',
                        borderRadius: 99,
                        border: `1px solid ${active ? 'var(--moss-deep)' : 'var(--line)'}`,
                        background: active ? 'var(--moss-deep)' : 'var(--card-solid)',
                        color: active ? 'var(--bg)' : 'var(--ink)',
                        fontSize: 12,
                        fontFamily: 'var(--font-serif)',
                        cursor: done ? 'default' : 'pointer',
                        transition: 'all .15s',
                      }}
                    >
                      {opt}
                    </button>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
      {!done && (
        <div style={{ display: 'flex', gap: 8, marginTop: 14, alignItems: 'center' }}>
          <button
            className="btn-reset"
            disabled={!complete || busy}
            onClick={submit}
            style={{
              padding: '8px 16px',
              borderRadius: 8,
              background: complete ? 'var(--moss-deep)' : 'var(--bg-2)',
              color: complete ? 'var(--bg)' : 'var(--ink-mute)',
              fontSize: 12,
              cursor: complete && !busy ? 'pointer' : 'default',
              opacity: busy ? .7 : 1,
              transition: 'all .2s',
            }}
          >
            {busy ? 'Running…' : 'Continue'}
          </button>
          <button
            className="btn-reset"
            disabled={busy}
            onClick={async () => {
              // Skip → submit with default first options
              const defaults = {};
              fields.forEach(f => { defaults[f.id] = f.options[0]; });
              setAnswers(defaults);
              setBusy(true);
              await onSubmit(defaults, originalText);
            }}
            style={{
              padding: '8px 14px',
              borderRadius: 8,
              border: '1px solid var(--line)',
              background: 'transparent',
              color: 'var(--ink-soft)',
              fontSize: 12,
              cursor: busy ? 'default' : 'pointer',
            }}
          >
            Skip · use defaults
          </button>
        </div>
      )}
    </div>
  );
}

// ---- Research plan card — shown at the top of the AI message ----
// Renders the model's declared plan (from the plan_research tool) as a
// checklist. Steps tick from 'pending' → 'done' as the corresponding
// tools fire (server tracks via tools_planned overlap).
function ResearchPlanCard({ plan }) {
  if (!plan || !plan.steps || plan.steps.length === 0) return null;
  const total = plan.steps.length;
  const done = plan.steps.filter(s => s.status === 'done').length;
  const isComplete = done === total;
  return (
    <div style={{
      border: '1px solid var(--line)',
      background: 'var(--card-solid)',
      borderRadius: 12,
      padding: '12px 14px',
      marginBottom: 14,
      boxShadow: 'var(--shadow-sm)',
    }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: plan.assumptions && plan.assumptions.length ? 4 : 10 }}>
        <span className="label label-moss">Plan</span>
        {plan.title && (
          <span style={{ fontSize: 13, color: 'var(--ink)', fontWeight: 500 }}>{plan.title}</span>
        )}
        <span style={{ marginLeft: 'auto', fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--ink-mute)' }}>
          {done} / {total}
        </span>
      </div>
      {plan.assumptions && plan.assumptions.length > 0 && (
        <div style={{ marginBottom: 10, paddingLeft: 0 }}>
          <div className="label" style={{ color: 'var(--ink-mute)', marginBottom: 4 }}>Assumptions</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
            {plan.assumptions.map((a, i) => (
              <span key={i} style={{
                fontSize: 11, padding: '2px 8px', borderRadius: 99,
                background: 'var(--bg-2)', color: 'var(--ink-soft)',
                fontFamily: 'var(--font-mono)', letterSpacing: '.02em',
              }}>{a}</span>
            ))}
          </div>
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {plan.steps.map((step, i) => {
          const status = step.status || 'pending';
          const isDone = status === 'done';
          // The first non-done step is "in progress"
          const isInProgress = !isDone && plan.steps.slice(0, i).every(s => s.status === 'done');
          return (
            <div key={i} style={{
              display: 'flex', alignItems: 'flex-start', gap: 8,
              fontSize: 13, lineHeight: 1.4,
              color: isDone ? 'var(--ink-mute)' : 'var(--ink)',
            }}>
              <span style={{
                flexShrink: 0, marginTop: 2,
                width: 14, height: 14, borderRadius: '50%',
                border: isDone ? 'none' : '1.5px solid ' + (isInProgress ? 'var(--moss-deep)' : 'var(--line)'),
                background: isDone ? 'var(--moss-deep)' : 'transparent',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                color: '#fff', fontSize: 9, fontWeight: 600,
              }}>
                {isDone ? '✓' : ''}
              </span>
              <span style={{
                flex: 1,
                textDecoration: isDone ? 'line-through' : 'none',
                textDecorationColor: 'var(--line)',
              }}>
                {step.label}
              </span>
              {isInProgress && !isComplete && <Orbit size={11} />}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---- Single step card: one agentic iteration's text + the tools it called ----
// Intermediate steps render as compact "thinking" blocks; the final step
// (no further tool calls) renders prominently as the AI's actual answer.
function StepCard({ step, isLast }) {
  const isThinking = !step.done && isLast;
  // Intermediate (had-tools) steps are compact "phase" blocks. The final
  // step where the model wrote its answer renders prominently.
  const isPhase = step.done && !step.isFinal;
  return (
    <div className="fade-up" style={{
      borderLeft: isPhase ? '2px solid var(--line)' : 'none',
      paddingLeft: isPhase ? 14 : 0,
      marginBottom: 12,
      opacity: isPhase ? 0.85 : 1,
    }}>
      {isPhase && (
        <div className="label" style={{ marginBottom: 5, color: 'var(--ink-mute)' }}>
          Step {step.id} · thinking
        </div>
      )}
      {step.text && (
        <div style={{ position: 'relative', fontSize: isPhase ? 13 : 14 }}>
          <Markdown text={step.text} />
          {isThinking && (
            <span style={{
              display: 'inline-block', width: 7, height: 12,
              background: 'var(--moss-deep)', verticalAlign: 'middle', marginLeft: 3,
              animation: 'pulse 1s ease-in-out infinite',
            }} />
          )}
        </div>
      )}
      {step.tools && step.tools.length > 0 && (
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 8 }}>
          {step.tools.map((t, i) => (
            <SkillPill
              key={(t.slug || t.name) + '_' + i}
              skill={{ id: t.slug || t.name, label: t.name || t.slug }}
              stage={step.done ? 'done' : 'thinking'}
            />
          ))}
        </div>
      )}
    </div>
  );
}

// ---- Inline streaming row in the chat (step-by-step phases) ----
function InlineStreamingRow() {
  const { streaming, currentThread } = useStore();
  if (!streaming.active || (currentThread && streaming.threadId !== currentThread.id)) return null;
  const steps = streaming.steps || [];
  const activity = streaming.activity || [];
  const hasContent = steps.length > 0 || streaming.partial || activity.length > 0;

  return (
    <div className="fade-up" style={{ display: 'flex', gap: 10, padding: '4px 0', alignItems: 'flex-start' }}>
      <div style={{ flexShrink: 0, marginTop: 2 }}><InkuLogo size={20} /></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        {/* Live SDK TodoWrite progress card — appears above everything else
            so the user sees the plan + ticking progress as the agent works. */}
        {Array.isArray(streaming.todos) && streaming.todos.length > 0 && (
          <TodoListCard todos={streaming.todos} />
        )}
        {streaming.plan && <ResearchPlanCard plan={streaming.plan} />}
        {!hasContent && !streaming.plan && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--ink-mute)', fontSize: 13 }}>
            <Orbit size={11} />
            <span>thinking…</span>
          </div>
        )}
        {/* Steps (legacy /chat path) — rendered when present. */}
        {steps.map((step, i) => (
          <StepCard key={step.id} step={step} isLast={i === steps.length - 1} />
        ))}
        {/* /chat/v2 path: no steps emitted, but partial text streams live.
            Render the partial directly via Markdown. */}
        {steps.length === 0 && streaming.partial && (
          <Markdown text={streaming.partial} />
        )}
        {/* Live agent activity trail — always rendered while streaming so
            the user sees the empty state until tool calls arrive. */}
        <ActivityTrail activity={activity} />
        {(streaming.receipts || []).map(r => <ReceiptCard key={r.id} receipt={r} />)}
      </div>
    </div>
  );
}

// ---- Chat stream (all messages in this thread) ----
function ChatStream({ wide }) {
  const { currentMessages, uploadsInFlight, submitClarifier } = useStore();
  const scrollRef = React.useRef(null);
  React.useEffect(() => {
    scrollRef.current && (scrollRef.current.scrollTop = scrollRef.current.scrollHeight);
  }, [currentMessages.length]);

  if (!currentMessages.length && Object.keys(uploadsInFlight).length === 0) {
    return (
      <div style={{
        flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: wide ? '40px 22px 60px' : '40px 22px',
        textAlign: 'center', color: 'var(--ink-mute)',
      }}>
        <div style={{ maxWidth: wide ? 620 : 360 }} className="fade-up">
          <InkuLogo size={wide ? 52 : 36} />
          <div style={{
            fontFamily: 'var(--font-display)',
            fontSize: wide ? 40 : 17,
            fontWeight: wide ? 500 : 400,
            letterSpacing: wide ? '-0.02em' : 0,
            color: wide ? 'var(--ink)' : 'var(--ink-soft)',
            marginTop: wide ? 28 : 16,
            lineHeight: 1.15,
          }}>
            {wide ? <>A fresh thread.<br/><span style={{ color: 'var(--moss-deep)' }}>What are we launching?</span></>
                  : <>Drop a brief, a deck, or a CSV — <br/>or ask me to launch something.</>}
          </div>
          {wide && (
            <div style={{ fontSize: 14, color: 'var(--ink-soft)', marginTop: 14, lineHeight: 1.5 }}>
              Drop a brief, a deck, or a CSV — or tell me what you're working on. I'll draft the strategy, the creative, and the calendar on the canvas.
            </div>
          )}
          <div className="label" style={{ marginTop: wide ? 28 : 18 }}>Try</div>
          <div style={{
            display: 'flex',
            flexDirection: wide ? 'row' : 'column',
            flexWrap: 'wrap',
            justifyContent: 'center',
            gap: 6, marginTop: 10,
          }}>
            {[
              'Launch a campaign for BRAME for Dry January',
              'Generate 12 variants for Meta and TikTok',
              'Schedule a weekly Meta performance scan',
            ].map(s => <SuggestionChip key={s} text={s} />)}
          </div>
        </div>
      </div>
    );
  }

  return (
    <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: wide ? '24px 22px' : '20px 18px' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14, maxWidth: wide ? 720 : 'none', margin: wide ? '0 auto' : 0 }}>
        {currentMessages.map((m, msgIdx) => {
          // Find the most recent user message BEFORE this assistant message —
          // used as the "original text" to re-send after clarifier submit.
          const priorUser = [...currentMessages.slice(0, msgIdx)].reverse().find(x => x.role === 'user' && !x.isClarifierReply);
          const priorUserText = priorUser ? (priorUser.content || '') : '';

          return m.role === 'user' ? (
            <UserMsg key={m.id}>
              {m.attachments && m.attachments.length ? (
                <>
                  <div style={{ marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.1em', opacity: 0.75 }}>
                    ATTACHED · {m.attachments.length} FILE{m.attachments.length>1?'S':''}
                  </div>
                  {m.attachments.map(f => <div key={f.id} style={{ fontSize: 12, opacity: 0.9 }}>{f.name}</div>)}
                </>
              ) : m.isClarifierReply ? (
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, opacity: 0.85 }}>
                  <span style={{ opacity: 0.7 }}>Answered · </span>{m.content}
                </div>
              ) : m.content}
            </UserMsg>
          ) : (
            <div key={m.id} style={{ display: 'flex', gap: 10, padding: '4px 0', alignItems: 'flex-start' }}>
              <div style={{ flexShrink: 0, marginTop: 2 }}><InkuLogo size={20} /></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                {/* Persisted SDK TodoWrite list — at the top so the
                    "what the agent did" plan is visible before the prose. */}
                {Array.isArray(m.todos) && m.todos.length > 0 && (
                  <TodoListCard todos={m.todos} />
                )}
                {/* Plan card (if the model emitted one) — anchors the message visually. */}
                {m.plan && <ResearchPlanCard plan={m.plan} />}
                {/* Step-by-step phases when available; otherwise fall back to a single
                    markdown block (older messages persisted before the step model). */}
                {m.steps && m.steps.length > 0 ? (
                  m.steps.map((step, i) => (
                    <StepCard key={step.id ?? i} step={{ ...step, done: true }} isLast={i === m.steps.length - 1} />
                  ))
                ) : (
                  <>
                    {m.skills && m.skills.length > 0 && (
                      <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap', marginBottom: 8 }}>
                        <span className="label label-moss" style={{ marginRight: 2 }}>Routed</span>
                        {m.skills.map((s, i) => <SkillPill key={s + i} skill={{ id: s, label: s }} stage="done" />)}
                      </div>
                    )}
                    <Markdown text={m.content} />
                  </>
                )}
                {/* Agent activity trail — always rendered for assistant messages
                    so the user can see what tools/subagents fired (or that none did).
                    All driven by SSE events; nothing hardcoded per-tool. */}
                <ActivityTrail activity={m.activity || []} />
                {(m.receipts || [])
                  .filter(r => r.kind === 'brand-receipts' || r.kind === 'data-receipts')
                  .map(r => <ReceiptCard key={r.id} receipt={r} />)}
                {m.clarifier && (
                  <ClarifierCard
                    clarifier={m.clarifier}
                    originalText={priorUserText}
                    onSubmit={submitClarifier}
                    done={!m.awaitingClarifier}
                    selectedAnswers={m.clarifierAnswers}
                  />
                )}
              </div>
            </div>
          );
        })}
        {Object.entries(uploadsInFlight).map(([id, u]) => (
          <UserMsg key={id}>
            <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
              <Orbit size={11} />
              <span style={{ fontSize: 12 }}>Parsing {u.name}…</span>
            </div>
          </UserMsg>
        ))}
        <InlineStreamingRow />
      </div>
    </div>
  );
}

function SuggestionChip({ text }) {
  const { sendMessage } = useStore();
  return (
    <button className="btn-reset" onClick={() => sendMessage(text)} style={{
      padding: '7px 12px', borderRadius: 99,
      border: '1px solid var(--line)', background: 'var(--card-solid)',
      color: 'var(--ink-soft)', fontSize: 12, cursor: 'pointer',
      textAlign: 'center', fontFamily: 'var(--font-serif)',
    }}
    onMouseEnter={e => { e.currentTarget.style.background = 'var(--moss-glow)'; e.currentTarget.style.color = 'var(--moss-deep)'; }}
    onMouseLeave={e => { e.currentTarget.style.background = 'var(--card-solid)'; e.currentTarget.style.color = 'var(--ink-soft)'; }}>
      "{text}"
    </button>
  );
}

// ============================================================
// ThreadView — the main chat + canvas screen
// ============================================================
function ThreadView() {
  const { currentThread, currentArtifacts, currentMessages, sendMessage, streaming } = useStore();

  if (!currentThread) {
    return <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-mute)' }}>
      <div style={{ textAlign: 'center' }}>
        <InkuLogo size={44} />
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 20, marginTop: 14, color: 'var(--ink-soft)' }}>Pick a thread or create one to start.</div>
      </div>
    </div>;
  }

  const lastSkills = currentArtifacts.reduce((n, a) => n + (a.kind === 'brief' ? 7 : a.kind === 'variant-matrix' ? 4 : 1), 0);

  // The canvas reveals once something is actually worth showing: an artifact
  // exists, or the assistant is streaming *and not still gathering clarifier
  // answers*. A clarifier-only turn stays in chat-only mode so the user's
  // attention is on the questions.
  const awaitingClarifier = currentMessages.some(m => m.role === 'assistant' && m.awaitingClarifier);
  const streamingHere = streaming.active && streaming.threadId === currentThread.id;
  const streamingClarifier = streamingHere && streaming.clarifier;
  const canvasActive =
    currentArtifacts.length > 0 ||
    (streamingHere && !streamingClarifier && !awaitingClarifier);

  // Zero-state landing: fresh thread, nothing has streamed, no uploads in
  // flight. Takes over the whole column so the composer can be centered.
  const isLanding = !canvasActive && !currentMessages.length && !streamingHere;

  if (isLanding) {
    return (
      <div style={{
        width: '100%', flexShrink: 0,
        display: 'flex', flexDirection: 'column',
        background: 'var(--bg)', height: '100vh', minWidth: 0,
      }}>
        <LandingHome />
      </div>
    );
  }

  return (
    <>
      <div style={{
        width: canvasActive ? 440 : '100%',
        flexShrink: 0, display: 'flex', flexDirection: 'column',
        borderRight: canvasActive ? '1px solid var(--line-soft)' : 'none',
        background: 'var(--bg)', height: '100vh',
        transition: 'width .6s cubic-bezier(.2,.7,.2,1), border-color .3s',
      }}>
        <div style={{
          padding: '20px 22px 12px',
          borderBottom: '1px solid var(--line-soft)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        }}>
          <div style={{ flex: 1, minWidth: 0, maxWidth: canvasActive ? 'none' : 760, margin: canvasActive ? 0 : '0 auto', width: '100%' }}>
            <div className="label">Thread</div>
            <EditableTitle title={currentThread.title} threadId={currentThread.id} />
          </div>
        </div>
        <div style={{
          flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0,
          maxWidth: canvasActive ? 'none' : 760,
          width: '100%',
          margin: canvasActive ? 0 : '0 auto',
          transition: 'max-width .6s cubic-bezier(.2,.7,.2,1)',
        }}>
          <ChatStream wide={!canvasActive} />
          <Composer onSend={sendMessage} />
        </div>
      </div>

      {canvasActive && (
        <div className="fade-in" style={{ flex: 1, display: 'flex', flexDirection: 'column', height: '100vh', minWidth: 0, animation: 'canvasIn .7s cubic-bezier(.2,.7,.2,1) both' }}>
          <CanvasHeader
            title={currentThread.title}
            subtitle={`${currentArtifacts.length} artifact${currentArtifacts.length!==1?'s':''} · ${lastSkills} skills routed`}
            right={
              <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
                <Icon name="route" size={13} stroke={1.5} />
                <span className="label">{lastSkills} skills</span>
              </div>
            } />
          <div style={{ flex: 1, overflowY: 'auto', position: 'relative' }}>
            <div style={{ maxWidth: 880, margin: '0 auto', padding: '20px 32px 80px', display: 'flex', flexDirection: 'column', gap: 16 }}>
              {currentArtifacts.map(a => <Artifact key={a.id} artifact={a} />)}
              {currentArtifacts.some(a => ['brief','concepts','calendar','variant-matrix'].includes(a.kind)) && (
                <HandoffCard />
              )}
            </div>
          </div>
        </div>
      )}
    </>
  );
}

function EditableTitle({ title, threadId }) {
  const { renameThread } = useStore();
  const [editing, setEditing] = React.useState(false);
  const [value, setValue] = React.useState(title);
  React.useEffect(() => setValue(title), [title]);

  if (editing) {
    return (
      <input autoFocus value={value} onChange={e => setValue(e.target.value)}
        onBlur={() => { setEditing(false); if (value.trim() && value !== title) renameThread(threadId, value.trim()); }}
        onKeyDown={e => { if (e.key === 'Enter') e.currentTarget.blur(); if (e.key === 'Escape') { setValue(title); setEditing(false); } }}
        style={{ border: 'none', outline: 'none', background: 'transparent',
          fontFamily: 'var(--font-display)', fontSize: 17, color: 'var(--ink)', fontWeight: 300, width: '100%',
          borderBottom: '1px solid var(--moss-deep)', padding: '1px 0' }} />
    );
  }
  return (
    <button className="btn-reset" onClick={() => setEditing(true)} style={{
      fontFamily: 'var(--font-display)', fontSize: 17, color: 'var(--ink)', fontWeight: 300,
      textAlign: 'left', cursor: 'text', padding: 0, marginTop: 2,
      overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', width: '100%',
    }}>{title}</button>
  );
}

function EmptyCanvas() {
  return (
    <div style={{ padding: '80px 20px', textAlign: 'center' }}>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 300, fontSize: 38, color: 'var(--ink)', letterSpacing: '-0.02em', lineHeight: 1.1 }}>
        <span style={{ color: 'var(--moss-deep)' }}>A blank canvas.</span><br/>
        Send a message to start.
      </div>
      <div style={{ fontFamily: 'var(--font-serif)', fontSize: 15, color: 'var(--ink-soft)', marginTop: 20, maxWidth: 420, margin: '20px auto 0', lineHeight: 1.5 }}>
        Everything Inku generates — briefs, concepts, calendars, variants — lands here as a stacked artifact you can open, edit, and ship.
      </div>
    </div>
  );
}

// ============================================================
// AgentsView — scheduled intelligence panel
// ============================================================
function AgentsView() {
  const { agents, toggleAgent, deleteAgent, createAgent, route, navigate } = useStore();
  const [creatorOpen, setCreatorOpen] = React.useState(false);

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', height: '100vh' }}>
      <CanvasHeader title="Scheduled intelligence"
        subtitle="Recurring agents that run on their own schedule and surface briefings"
        right={
          <button className="btn-reset" onClick={() => setCreatorOpen(true)} style={{
            padding: '8px 14px', borderRadius: 8,
            background: 'var(--moss-deep)', color: 'var(--bg)', fontSize: 12,
            display: 'flex', gap: 6, alignItems: 'center', cursor: 'pointer',
          }}>
            <Icon name="plus" size={13} /> Schedule agent
          </button>
        } />
      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ maxWidth: 880, margin: '0 auto', padding: '22px 32px 80px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {agents.map(a => (
              <AgentRow key={a.id} agent={a}
                active={route.agentId === a.id}
                onOpen={() => navigate(`/agents/${a.id}`)}
                onToggle={() => toggleAgent(a.id)}
                onDelete={() => { if (confirm(`Delete "${a.title}"?`)) deleteAgent(a.id); }} />
            ))}
          </div>

          {route.agentId && <AgentDetail agentId={route.agentId} />}

          {creatorOpen && <AgentCreator onClose={() => setCreatorOpen(false)} onCreate={async (payload) => { await createAgent(payload); setCreatorOpen(false); }} />}
        </div>
      </div>
    </div>
  );
}

function AgentRow({ agent, active, onOpen, onToggle, onDelete }) {
  const live = agent.status === 'live';
  return (
    <div style={{
      padding: 14, borderRadius: 10,
      background: active ? 'var(--moss-glow)' : (live ? 'var(--moss-glow)' : 'var(--card-solid)'),
      border: (live || active) ? '1.5px solid var(--moss-deep)' : '1px solid var(--card-border)',
      display: 'flex', gap: 14, alignItems: 'flex-start',
    }}>
      <button className="btn-reset" onClick={onOpen}
        style={{
          flex: 1, display: 'flex', gap: 14, alignItems: 'flex-start',
          cursor: 'pointer', textAlign: 'left', minWidth: 0,
        }}>
        <div style={{
          width: 34, height: 34, borderRadius: '50%', flexShrink: 0,
          background: live ? 'var(--moss-deep)' : 'var(--bg-2)',
          color: live ? 'var(--bg)' : 'var(--ink-mute)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          position: 'relative',
        }}>
          <Icon name={live ? 'bell' : agent.status === 'paused' ? 'pause' : 'clock'} size={15} />
          {agent.unread && <span className="pulse" style={{ position: 'absolute', top: -2, right: -2, width: 10, height: 10, borderRadius: '50%', background: 'var(--accent-warm)', border: '2px solid var(--card-solid)' }} />}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--font-serif)', fontSize: 16, color: 'var(--ink)', lineHeight: 1.25, marginBottom: 4 }}>{agent.title}</div>
          {(live || agent.status === 'paused') && (
            <div style={{ display: 'flex', gap: 6, marginBottom: 6 }}>
              {live && <span style={{ padding: '2px 7px', borderRadius: 99, background: 'var(--moss-deep)', color: 'var(--bg)', fontSize: 9, fontFamily: 'var(--font-mono)', letterSpacing: '.12em' }}>NEW</span>}
              {agent.status === 'paused' && <span className="label">paused</span>}
            </div>
          )}
          <div style={{ fontSize: 12, color: 'var(--ink-soft)', marginBottom: 6, lineHeight: 1.45 }}>{agent.desc}</div>
          <div className="label">{agent.cadence} · last run {agent.lastRun}</div>
        </div>
      </button>
      <div style={{ display: 'flex', gap: 4, flexShrink: 0 }}>
        <button className="btn-reset" title={agent.status === 'paused' ? 'Resume' : 'Pause'} onClick={onToggle}
          style={{ padding: 6, borderRadius: 6, color: 'var(--ink-mute)', cursor: 'pointer' }}>
          <Icon name={agent.status === 'paused' ? 'play' : 'pause'} size={14} />
        </button>
        <button className="btn-reset" title="Delete" onClick={onDelete}
          style={{ padding: 6, borderRadius: 6, color: 'var(--ink-mute)', cursor: 'pointer' }}>
          <Icon name="x" size={14} />
        </button>
      </div>
    </div>
  );
}

function AgentDetail({ agentId }) {
  const { approveProposal } = useStore();
  const [briefing, setBriefing] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    let ok = true;
    setLoading(true);
    api.getLatestBriefing(agentId).then(b => { if (ok) { setBriefing(b); setLoading(false); } });
    return () => { ok = false; };
  }, [agentId]);

  if (loading) return (
    <CardShell kind="briefing" title="loading…">
      <div style={{ padding: '24px 0', textAlign: 'center', color: 'var(--ink-mute)' }}><Orbit size={14} /></div>
    </CardShell>
  );
  if (!briefing) return (
    <CardShell kind="briefing" title="no recent briefing">
      <div style={{ fontSize: 13, color: 'var(--ink-soft)' }}>This agent hasn't produced a briefing yet — it'll run on schedule and surface here automatically.</div>
    </CardShell>
  );

  const tone = { warn: '#C67B4A', good: 'var(--moss-deep)', info: 'var(--ink-soft)' };
  return (
    <>
      <CardShell kind={`briefing · ${briefing.runAt}`} title={briefing.headline}>
        <p style={{ margin: 0, fontFamily: 'var(--font-serif)', fontSize: 16, lineHeight: 1.55, color: 'var(--ink)' }}>{briefing.summary}</p>
        <div style={{ marginTop: 16 }}>
          <div className="label label-moss" style={{ marginBottom: 8 }}>What I noticed</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {briefing.observations.map((o, i) => (
              <div key={i} style={{ padding: '8px 10px', borderRadius: 8, background: 'var(--bg)', border: '1px solid var(--line-soft)', display: 'flex', gap: 10, alignItems: 'center', fontSize: 12, color: 'var(--ink-soft)' }}>
                <span style={{ color: tone[o.kind], fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.14em', textTransform: 'uppercase', width: 46 }}>{o.kind}</span>
                <span style={{ flex: 1 }}>{o.text}</span>
              </div>
            ))}
          </div>
        </div>
      </CardShell>
      <CardShell kind="proposals · ready to approve" title="three replacement directions">
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {briefing.proposals.map((p, i) => (
            <div key={p.id} style={{ padding: 14, borderRadius: 10, background: 'var(--bg)', border: '1px solid var(--line)', display: 'flex', gap: 14, alignItems: 'center' }}>
              <div style={{ width: 46, height: 46, borderRadius: '50%', background: `conic-gradient(var(--moss-deep) ${p.score * 3.6}deg, var(--bg-2) 0)`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--card-solid)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-display)', fontSize: 14, color: 'var(--moss-deep)' }}>{p.score}</div>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontFamily: 'var(--font-serif)', fontSize: 17, color: 'var(--ink)', lineHeight: 1.2 }}>{p.title}</div>
                <div className="label" style={{ marginTop: 4 }}>{p.channels.join(' · ')} · {p.tags.join(' · ')}</div>
              </div>
              <div style={{ display: 'flex', gap: 6 }}>
                <button className="btn-reset" onClick={() => approveProposal(p.id)} style={{ padding: '7px 12px', borderRadius: 7, background: 'var(--moss-deep)', color: 'var(--bg)', fontSize: 11, cursor: 'pointer' }}>Approve & brief</button>
                <button className="btn-reset" style={{ padding: '7px 12px', borderRadius: 7, border: '1px solid var(--line)', color: 'var(--ink-soft)', fontSize: 11, cursor: 'pointer' }}>Tweak</button>
              </div>
            </div>
          ))}
        </div>
      </CardShell>
    </>
  );
}

function AgentCreator({ onClose, onCreate }) {
  const [title, setTitle] = React.useState('');
  const [desc, setDesc] = React.useState('');
  const [cadence, setCadence] = React.useState('Every Monday · 09:00');
  const [busy, setBusy] = React.useState(false);

  return (
    <CardShell kind="schedule an agent" title="new recurring job"
      actions={<button className="btn-reset" onClick={onClose} style={{ padding: 5, color: 'var(--ink-mute)', cursor: 'pointer' }}><Icon name="x" size={13} /></button>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        <input autoFocus value={title} onChange={e => setTitle(e.target.value)} placeholder="Title — e.g. Competitor watch"
          style={{ padding: '10px 12px', borderRadius: 8, border: '1px solid var(--line)', fontSize: 14, fontFamily: 'var(--font-serif)', background: 'var(--bg)' }} />
        <textarea value={desc} onChange={e => setDesc(e.target.value)} placeholder="What should this agent do? e.g. Scan Seedlip and Lyre's ads weekly, summarise shifts, flag threats."
          style={{ padding: '10px 12px', borderRadius: 8, border: '1px solid var(--line)', fontSize: 13, fontFamily: 'var(--font-serif)', background: 'var(--bg)', minHeight: 70, resize: 'vertical' }} />
        <select value={cadence} onChange={e => setCadence(e.target.value)}
          style={{ padding: '10px 12px', borderRadius: 8, border: '1px solid var(--line)', fontSize: 13, background: 'var(--bg)', fontFamily: 'var(--font-mono)' }}>
          {['Every Monday · 09:00', 'Every Friday · 16:00', 'Daily · 08:00', 'First of month · 08:00', 'Quarterly'].map(c =>
            <option key={c}>{c}</option>
          )}
        </select>
        <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
          <button className="btn-reset" onClick={onClose} style={{ padding: '8px 14px', borderRadius: 7, border: '1px solid var(--line)', color: 'var(--ink-soft)', fontSize: 12, cursor: 'pointer' }}>Cancel</button>
          <button className="btn-reset" disabled={!title.trim() || busy} onClick={async () => { setBusy(true); await onCreate({ title: title.trim(), desc: desc.trim(), cadence }); setBusy(false); }}
            style={{ padding: '8px 14px', borderRadius: 7, background: title.trim() ? 'var(--moss-deep)' : 'var(--bg-2)', color: title.trim() ? 'var(--bg)' : 'var(--ink-mute)', fontSize: 12, cursor: title.trim() ? 'pointer' : 'default' }}>
            {busy ? 'Scheduling…' : 'Schedule agent'}
          </button>
        </div>
      </div>
    </CardShell>
  );
}

Object.assign(window, { ThreadView, AgentsView, Artifact });
