// ==========================================================================
// Chat stream atoms: user message, AI message, skill router pills, file drops
// ==========================================================================

function UserMsg({ children }) {
  return (
    <div className="fade-up" style={{ display: 'flex', justifyContent: 'flex-end', padding: '4px 0' }}>
      <div style={{
        maxWidth: '88%',
        padding: '10px 14px',
        background: 'var(--moss-deep)',
        color: 'var(--bg)',
        borderRadius: '14px 14px 4px 14px',
        fontSize: 14, lineHeight: 1.45,
      }}>
        {children}
      </div>
    </div>
  );
}

function AIMsg({ children, streaming, small }) {
  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, paddingTop: 3,
        fontFamily: small ? 'inherit' : 'var(--font-serif)',
        fontSize: small ? 13 : 16,
        lineHeight: 1.5, color: 'var(--ink)',
      }}>
        {children}
        {streaming && <span style={{ display: 'inline-block', width: 8, height: 14, background: 'var(--moss-deep)', verticalAlign: 'middle', marginLeft: 3, animation: 'pulse 1s ease-in-out infinite' }} />}
      </div>
    </div>
  );
}

// ==== Skill router pill ====
// stages: "pending" | "thinking" | "done"
//
// Two skills are visually distinct ("moat"): consulting-brand, consulting-data.
// They are rendered with a filled background because they represent Inku's
// defensibility — retrieval across the customer's brand corpus and their
// performance data. Every other skill is a prompt-shaped generator.
// See api.js chat() MOAT comment block for where this is wired on the backend.
const SKILL_LABELS = {
  'consulting-brand': 'Consulting brand',
  'consulting-data':  'Consulting data',
  'document-intelligence': 'Document intelligence',
  'customer-research': 'Customer research',
  'marketing-psychology': 'Marketing psychology',
  'positioning': 'Positioning',
  'messaging-architecture': 'Messaging architecture',
  'ad-creative': 'Ad creative',
  'launch-strategy': 'Launch strategy',
  'social-content': 'Social content',
  'variant-generation': 'Variant generation',
  'performance-hypothesis': 'Performance hypothesis',
  'fatigue-detection': 'Fatigue detection',
  'brand-context': 'Brand context',
};
const MOAT_SKILLS = new Set(['consulting-brand', 'consulting-data']);

function SkillPill({ skill, stage }) {
  const id = skill.id || skill.label;
  const label = SKILL_LABELS[id] || skill.label || id;
  const isMoat = MOAT_SKILLS.has(id);

  // Moat pills lean warmer (accent-warm) when active, and always show filled.
  const bg =
    stage === 'thinking' ? (isMoat ? 'var(--accent-warm)' : 'var(--moss-glow)')
    : stage === 'done'   ? (isMoat ? 'var(--moss-deep)'   : 'var(--bg-2)')
    : (isMoat ? 'var(--card-solid)' : 'transparent');
  const color =
    stage === 'thinking' ? (isMoat ? '#fff' : 'var(--moss-deep)')
    : stage === 'done'   ? (isMoat ? 'var(--bg)' : 'var(--ink)')
    : (isMoat ? 'var(--accent-warm-2)' : 'var(--ink-mute)');
  const border = isMoat
    ? `1px solid ${stage === 'done' ? 'var(--moss-deep)' : 'var(--accent-warm)'}`
    : '1px solid var(--line)';

  return (
    <div style={{
      display: 'inline-flex', gap: 6, alignItems: 'center',
      padding: '3px 9px 3px 7px',
      borderRadius: 99,
      border, background: bg, color,
      fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.04em',
      transition: 'all .4s',
      opacity: stage === 'pending' ? (isMoat ? 0.85 : 0.45) : 1,
      fontWeight: isMoat ? 500 : 400,
    }}>
      {isMoat
        ? <span style={{ fontSize: 9, lineHeight: 1 }}>◆</span>
        : stage === 'thinking' ? <Orbit size={9}/> : stage === 'done' ? <Icon name="check" size={10} stroke={2.4}/> : <span style={{ width: 9, height: 9, borderRadius: '50%', border: '1px solid currentColor' }}/>}
      {isMoat && (stage === 'thinking') && <Orbit size={9}/>}
      {isMoat && (stage === 'done')     && <Icon name="check" size={10} stroke={2.4}/>}
      {label}
    </div>
  );
}

function SkillRouter({ skills, activeIndex }) {
  // activeIndex = number of completed skills. skills[activeIndex] is "thinking".
  return (
    <div className="fade-up" style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap', padding: '8px 0 4px 30px' }}>
      <span className="label" style={{ marginRight: 4 }}>routing</span>
      {skills.map((s, i) => (
        <React.Fragment key={s.id}>
          <SkillPill skill={s} stage={i < activeIndex ? 'done' : i === activeIndex ? 'thinking' : 'pending'} />
          {i < skills.length - 1 && <span style={{ color: 'var(--ink-mute)', fontFamily: 'var(--font-mono)', fontSize: 10 }}>→</span>}
        </React.Fragment>
      ))}
    </div>
  );
}

// ==== File drop zone (used in composer + flow 1 empty state) ====
function DropZone({ onDrop, children }) {
  const [over, setOver] = React.useState(false);
  return (
    <div
      onDragOver={e => { e.preventDefault(); setOver(true); }}
      onDragLeave={() => setOver(false)}
      onDrop={e => { e.preventDefault(); setOver(false); onDrop && onDrop(); }}
      onClick={() => onDrop && onDrop()}
      style={{
        border: over ? '1.5px dashed var(--moss-deep)' : '1.5px dashed var(--line)',
        background: over ? 'var(--moss-glow)' : 'transparent',
        borderRadius: 14,
        padding: 28,
        textAlign: 'center',
        cursor: 'pointer',
        transition: 'all .2s',
      }}>
      {children}
    </div>
  );
}

// ==== Markdown rendering ====
// Assistant text comes back as markdown (bold, lists, tables, code). marked
// + DOMPurify are loaded globally via CDN in index.html. We sanitize with
// DOMPurify, then DOMParser turns the HTML string into inert DOM nodes
// (script tags are not executed by 'text/html' parsing), which we move
// into our ref. No innerHTML.
function Markdown({ text }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const node = ref.current;
    if (!node) return;
    while (node.firstChild) node.removeChild(node.firstChild);
    if (!text) return;
    if (typeof window.marked === 'undefined' || typeof window.DOMPurify === 'undefined') {
      node.textContent = text;
      return;
    }
    const html = window.marked.parse(text, { breaks: true, gfm: true, mangle: false, headerIds: false });
    const safe = window.DOMPurify.sanitize(html);
    const parsed = new DOMParser().parseFromString(safe, 'text/html');
    const frag = document.createDocumentFragment();
    while (parsed.body.firstChild) frag.appendChild(parsed.body.firstChild);
    node.appendChild(frag);
  }, [text]);
  return <div className="md-body" ref={ref} />;
}

Object.assign(window, { UserMsg, AIMsg, SkillPill, SkillRouter, DropZone, Markdown });
