/* Pulse — AI assistant powered by window.claude.complete
   A right-side slide-over with quick actions, chat, and apply-suggestions. */

function PulsePanel({ open, onClose, tasks, allTasks, onApply, onSelectTask }) {
  const [history, setHistory] = React.useState([
    { role: 'assistant', content: "Hi Alex — I'm Pulse. I can plan your day, summarise threads, draft replies, triage incoming work, or balance workload. Try a chip below, or just ask." }
  ]);
  const [input, setInput]   = React.useState('');
  const [busy, setBusy]     = React.useState(false);
  const [activeAction, setActiveAction] = React.useState(null);
  const scrollRef = React.useRef(null);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [history, busy]);

  if (!open) return null;

  // ─── Workspace context for Claude ───
  const buildContext = () => {
    const compact = (t) => ({
      id: t.id, ticket: t.ticket, title: t.title,
      space: spaceById(t.spaceId)?.name,
      status: statusById(t.statusId)?.title,
      priority: t.priority, type: t.type,
      due: t.dueDate, est_mins: t.estimateMins,
      assignees: t.assignees.map(id => userById(id)?.name),
      tags: t.tags.map(id => tagById(id)?.name),
      clients: t.clients.map(id => clientById(id)?.name),
      important: t.important, my_day: t.myDay,
      desc: (t.description || '').slice(0, 200),
    });
    return {
      today: TODAY.toISOString().slice(0, 10),
      current_user: { id: 1, name: 'Alex Harley', role: 'Lead clinician' },
      workspace: 'Harley Mindcare · clinical task management',
      spaces: D.spaces.map(s => ({ name: s.name, prefix: s.prefix, sla_days: s.sla })),
      statuses: D.statuses.map(s => s.title),
      users: D.users.map(u => ({ name: u.name, role: u.role })),
      visible_tasks: tasks.slice(0, 30).map(compact),
      all_tasks_count: allTasks.length,
    };
  };

  const systemPrompt = () => `You are Pulse, an AI assistant inside a clinical task-management product called Taskhub (used at a UK private mental-health practice). Your job is to help Alex Harley and her team triage, plan, distribute and write tasks.

Guidelines:
- Be concise. 2–4 short paragraphs max, OR a tight numbered list — never both unless asked.
- Be specific. Use ticket IDs and names from the workspace. Don't generalise.
- Show your reasoning briefly when prioritising or balancing — one sentence, not a lecture.
- Tone: warm but professional. UK English. No marketing language. No emoji unless the user uses one.
- For clinical context, default to safe, conservative recommendations and explicitly flag when something needs human judgement (safeguarding, risk, prescribing).
- When you suggest a concrete action that the app could apply, end your message with a JSON block:
\`\`\`apply
[{ "kind": "reassign", "task_id": 5, "to": "Priya Rao", "why": "..." }, ...]
\`\`\`
  Action kinds: "reassign", "set_priority", "set_status", "set_due", "snooze", "add_tag".
- Do NOT include the JSON block unless the user has confirmed they want changes.

Workspace context (live):
${JSON.stringify(buildContext(), null, 2)}`;

  const send = async (userMessage, label = null) => {
    if (!userMessage) return;
    setBusy(true); setActiveAction(label);
    const next = [...history, { role: 'user', content: userMessage, label }];
    setHistory(next);
    setInput('');
    try {
      const messages = next.filter(m => m.role !== 'system').map(m => ({ role: m.role, content: m.content }));
      const reply = await window.claude.complete({
        system: systemPrompt(),
        messages,
      });
      setHistory(h => [...h, { role: 'assistant', content: reply }]);
    } catch (err) {
      setHistory(h => [...h, { role: 'assistant', content: `Sorry — I couldn't reach the language model just then. ${(err && err.message) || ''}` }]);
    } finally {
      setBusy(false); setActiveAction(null);
    }
  };

  const quickActions = [
    { key: 'plan',     label: 'Plan my day',        glyph: '☀', prompt: "Look at my visible tasks and give me a focused, ranked plan for today. Group into 'Right now' (next 90 minutes), 'After lunch', and 'If time'. Briefly explain why each item is where it is. Take account of urgency, due dates, and dependencies." },
    { key: 'balance',  label: 'Balance workload',    glyph: '⚖', prompt: "Look at the team's open work and estimates for this week. Identify who is over-capacity and who has slack. Suggest 2–4 specific reassignments to even things out, with one-line reasoning each. End with the 'apply' JSON block ready to execute." },
    { key: 'standup',  label: 'Standup',             glyph: '☕', prompt: "Generate a short standup for me (Alex) covering: ✓ done yesterday (use my completed tasks), ▸ on today, ⚠ blocked. Keep it under 80 words. Plain text, no JSON." },
    { key: 'risk',     label: 'Risk scan',           glyph: '⚠', prompt: "Sweep my visible tasks for anything that smells like safeguarding, risk, prescribing concerns, urgent clinical contact, or DNA escalation. List the 3–5 highest-concern items with ticket ID and one-line reason. Mark any that need *immediate* human escalation." },
    { key: 'summary',  label: 'Weekly summary',      glyph: '◐', prompt: "Write a one-paragraph weekly summary I could share with the practice manager: volume handled, top themes, anything notable in compliance / billing / care. Keep it factual and under 100 words." },
    { key: 'draft',    label: 'Draft reply',         glyph: '✎', prompt: "I need to draft a warm but professional acknowledgement letter to Dr Levin confirming I've received the referral for Mrs Aldridge, will call her today, and will write again after triage. Sign as Alex Harley, Harley Mindcare. Plain text, ~80 words." },
  ];

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0,
      background: 'rgba(15,23,42,0.4)', backdropFilter: 'blur(4px)',
      display: 'flex', justifyContent: 'flex-end', zIndex: 220,
    }}>
      <div onClick={e => e.stopPropagation()} className="slide-in-r" style={{
        width: 460, height: '100vh',
        background: 'rgb(var(--surface))',
        borderLeft: '1px solid rgb(var(--rule))',
        display: 'flex', flexDirection: 'column',
        boxShadow: 'var(--sh-pop)',
      }}>
        {/* Header */}
        <div style={{
          padding: '14px 18px', borderBottom: '1px solid rgb(var(--rule))',
          display: 'flex', alignItems: 'center', gap: 12,
          background: 'linear-gradient(135deg, rgb(var(--accent-soft)) 0%, transparent 100%)',
        }}>
          <div style={{
            width: 36, height: 36, borderRadius: 10,
            background: 'linear-gradient(135deg, rgb(var(--accent)), rgb(var(--berry)))',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            color: 'white', fontWeight: 700, fontSize: 17,
            boxShadow: 'var(--sh-sm)',
          }}>✦</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700, color: 'rgb(var(--ink))', display: 'flex', alignItems: 'center', gap: 6 }}>
              Pulse
              <span style={{ fontSize: 9.5, padding: '1px 7px', background: 'rgb(var(--accent))', color: 'white', borderRadius: 999, fontWeight: 700, letterSpacing: '0.04em' }}>AI</span>
            </h3>
            <p style={{ margin: '2px 0 0', fontSize: 11.5, color: 'rgb(var(--muted))' }}>Knows your tasks, team, and schedule</p>
          </div>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10.5, fontFamily: 'JetBrains Mono, monospace', color: 'rgb(var(--muted))', padding: '3px 8px', background: 'rgb(var(--paper-2))', borderRadius: 999 }}>
            <span style={{ width: 5, height: 5, background: 'rgb(var(--forest))', borderRadius: '50%' }} />online
          </span>
          <button onClick={onClose} style={{
            fontSize: 20, color: 'rgb(var(--muted))', padding: '0 6px',
            borderRadius: 6, lineHeight: 1,
          }}>×</button>
        </div>

        {/* Quick actions */}
        <div style={{ padding: '12px 16px', borderBottom: '1px solid rgb(var(--rule))', background: 'rgb(var(--bg))' }}>
          <p style={{ margin: '0 0 8px', fontSize: 10.5, fontWeight: 600, color: 'rgb(var(--muted))', letterSpacing: '0.06em', textTransform: 'uppercase' }}>Try</p>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {quickActions.map(a => (
              <button key={a.key} onClick={() => send(a.prompt, a.label)} disabled={busy}
                style={{
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                  padding: '5px 12px',
                  fontSize: 12, fontWeight: 600,
                  background: activeAction === a.label ? 'rgb(var(--accent))' : 'rgb(var(--surface))',
                  color: activeAction === a.label ? 'white' : 'rgb(var(--ink-2))',
                  border: '1px solid ' + (activeAction === a.label ? 'rgb(var(--accent))' : 'rgb(var(--rule))'),
                  borderRadius: 999,
                  cursor: busy ? 'default' : 'pointer', opacity: busy && activeAction !== a.label ? 0.55 : 1,
                  transition: 'all .14s',
                }}>
                <span>{a.glyph}</span>{a.label}
              </button>
            ))}
          </div>
        </div>

        {/* History */}
        <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: '14px 16px' }}>
          {history.map((m, i) => <Message key={i} message={m} onApply={onApply} onSelectTask={onSelectTask} />)}
          {busy && <ThinkingBubble action={activeAction} />}
        </div>

        {/* Input */}
        <form onSubmit={(e) => { e.preventDefault(); if (input.trim()) send(input.trim()); }} style={{
          padding: '12px 16px', borderTop: '1px solid rgb(var(--rule))',
          background: 'rgb(var(--surface))',
        }}>
          <div style={{
            display: 'flex', alignItems: 'flex-end', gap: 8,
            padding: '8px 8px 8px 14px',
            background: 'rgb(var(--bg))',
            border: '1px solid rgb(var(--rule))',
            borderRadius: 12,
            transition: 'border-color .14s, box-shadow .14s',
          }}>
            <textarea
              value={input}
              onChange={e => setInput(e.target.value)}
              onKeyDown={e => {
                if (e.key === 'Enter' && !e.shiftKey) {
                  e.preventDefault();
                  if (input.trim()) send(input.trim());
                }
              }}
              rows={1}
              placeholder="Ask Pulse anything about your tasks…"
              style={{
                flex: 1, resize: 'none', minHeight: 24, maxHeight: 120,
                border: 'none', background: 'transparent', padding: '4px 0',
                fontSize: 13.5, lineHeight: 1.5, outline: 'none',
                fontFamily: 'inherit',
              }}
              disabled={busy}
            />
            <button type="submit" disabled={busy || !input.trim()} className="btn btn-accent" style={{
              padding: '6px 14px', fontSize: 13,
              opacity: busy || !input.trim() ? 0.45 : 1,
              cursor: busy || !input.trim() ? 'default' : 'pointer',
            }}>{busy ? '…' : 'Send'}</button>
          </div>
          <p style={{ margin: '6px 4px 0', fontSize: 10.5, color: 'rgb(var(--muted))' }}>
            ⌘ J to toggle · responses use a fast model (Haiku) · pulse only sees the tasks you can see
          </p>
        </form>
      </div>
    </div>
  );
}

function Message({ message, onApply, onSelectTask }) {
  const isUser = message.role === 'user';
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: isUser ? 'flex-end' : 'flex-start', marginBottom: 14 }}>
      {isUser && message.label && (
        <span style={{ fontSize: 10.5, fontWeight: 700, color: 'rgb(var(--accent))', marginBottom: 4, letterSpacing: '0.04em', textTransform: 'uppercase' }}>{message.label}</span>
      )}
      {!isUser && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
          <span style={{
            width: 18, height: 18, borderRadius: 5,
            background: 'linear-gradient(135deg, rgb(var(--accent)), rgb(var(--berry)))',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            color: 'white', fontSize: 10, fontWeight: 700,
          }}>✦</span>
          <span style={{ fontSize: 11.5, fontWeight: 600, color: 'rgb(var(--muted))' }}>Pulse</span>
        </div>
      )}
      <div style={{
        maxWidth: isUser ? '85%' : '100%',
        background: isUser ? 'rgb(var(--accent))' : 'rgb(var(--paper-2) / 0.7)',
        color: isUser ? 'white' : 'rgb(var(--ink))',
        padding: '10px 14px',
        borderRadius: 14,
        borderTopRightRadius: isUser ? 4 : 14,
        borderTopLeftRadius:  isUser ? 14 : 4,
        fontSize: 13.5, lineHeight: 1.6,
      }}>
        {isUser
          ? <div style={{ whiteSpace: 'pre-wrap' }}>{message.label ? `Run "${message.label}"` : message.content}</div>
          : <PulseMarkdown text={message.content} onApply={onApply} onSelectTask={onSelectTask} />}
      </div>
    </div>
  );
}

function ThinkingBubble({ action }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14, animation: 'fadein .2s ease' }}>
      <span style={{
        width: 18, height: 18, borderRadius: 5,
        background: 'linear-gradient(135deg, rgb(var(--accent)), rgb(var(--berry)))',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        color: 'white', fontSize: 10, fontWeight: 700,
        animation: 'pulse-dot 1.4s infinite',
      }}>✦</span>
      <span style={{
        background: 'rgb(var(--paper-2) / 0.7)', borderTopLeftRadius: 4, borderRadius: 14,
        padding: '10px 14px', fontSize: 13, color: 'rgb(var(--muted))',
        display: 'inline-flex', alignItems: 'center', gap: 8,
      }}>
        <span style={{ display: 'inline-flex', gap: 3 }}>
          {[0, 1, 2].map(i => <span key={i} style={{
            width: 5, height: 5, borderRadius: '50%', background: 'rgb(var(--muted))',
            animation: `pulse-dot 1.2s ${i * 0.15}s infinite`,
          }} />)}
        </span>
        {action ? `Thinking · ${action}…` : 'Thinking…'}
      </span>
    </div>
  );
}

/* ── Markdown renderer + apply-action parsing ─────────────────────────── */
function PulseMarkdown({ text, onApply, onSelectTask }) {
  // Split out apply JSON block if present
  const applyMatch = text.match(/```apply\s*([\s\S]*?)```/);
  let mainText = text;
  let actions = null;
  if (applyMatch) {
    mainText = text.replace(applyMatch[0], '').trim();
    try { actions = JSON.parse(applyMatch[1].trim()); } catch (e) { actions = null; }
  }
  return (
    <>
      <div dangerouslySetInnerHTML={{ __html: renderPulseMd(mainText) }} />
      {actions && Array.isArray(actions) && actions.length > 0 && (
        <ActionBlock actions={actions} onApply={onApply} onSelectTask={onSelectTask} />
      )}
    </>
  );
}

function renderPulseMd(text) {
  let s = (text || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  // Headers
  s = s.replace(/^### (.*)$/gm, '<h4 style="margin: 14px 0 6px; font-size: 13.5px; font-weight: 700; color: rgb(var(--ink));">$1</h4>');
  s = s.replace(/^## (.*)$/gm,  '<h3 style="margin: 16px 0 8px; font-size: 14.5px; font-weight: 700; color: rgb(var(--ink));">$1</h3>');
  // Bold + italic + code
  s = s.replace(/`([^`]+)`/g, '<code style="font-family: \'JetBrains Mono\', monospace; font-size: 0.88em; padding: 1px 6px; background: rgba(0,0,0,0.06); border-radius: 4px;">$1</code>');
  s = s.replace(/\*\*([^*]+)\*\*/g, '<strong style="font-weight: 700;">$1</strong>');
  s = s.replace(/(?<!\w)\*([^*]+)\*(?!\w)/g, '<em>$1</em>');
  // Ticket id auto-link (simple)
  s = s.replace(/\b((?:INT|CARE|BILL|COMP|OPS|ROAD|NEW)-\d{4}-\d{4,5}|(?:INT|CARE|BILL|COMP|OPS|ROAD|NEW)-\d+)\b/g, '<span style="font-family: \'JetBrains Mono\', monospace; font-size: 0.9em; color: rgb(var(--accent)); font-weight: 600;">$1</span>');
  // Lists
  s = s.replace(/(^|\n)((?:[\-\*\u2022\u25b8\u2192\u2713\u26a0\u2718\u2733]\s.+\n?)+)/g, (m, lead, blk) => {
    const items = blk.trim().split('\n').map(l => l.replace(/^[\-\*\u2022\u25b8\u2192\u2713\u26a0\u2718\u2733]\s/, '').trim()).filter(Boolean);
    return lead + '<ul style="margin: 6px 0 8px; padding-left: 18px;">' + items.map(i => `<li style="margin-bottom: 3px;">${i}</li>`).join('') + '</ul>';
  });
  s = s.replace(/(^|\n)((?:\d+\.\s.+\n?)+)/g, (m, lead, blk) => {
    const items = blk.trim().split('\n').map(l => l.replace(/^\d+\.\s/, '').trim()).filter(Boolean);
    return lead + '<ol style="margin: 6px 0 8px; padding-left: 22px;">' + items.map(i => `<li style="margin-bottom: 3px;">${i}</li>`).join('') + '</ol>';
  });
  // Paragraphs
  s = s.split(/\n{2,}/).map(p => p.trim() ? (p.match(/^<(ul|ol|h\d)/) ? p : `<p style="margin: 0 0 8px;">${p.replace(/\n/g, '<br>')}</p>`) : '').join('');
  return s;
}

function ActionBlock({ actions, onApply, onSelectTask }) {
  const [appliedKeys, setAppliedKeys] = React.useState({});
  const apply = (i, a) => {
    onApply?.(a);
    setAppliedKeys(k => ({ ...k, [i]: true }));
  };
  const describeAction = (a) => {
    const t = D.tasks.find(t => t.id === a.task_id);
    const ref = t ? <span style={{ fontFamily: 'JetBrains Mono, monospace', fontWeight: 600 }}>{t.ticket}</span> : `#${a.task_id}`;
    if (a.kind === 'reassign')     return <>Reassign {ref} → <strong>{a.to}</strong></>;
    if (a.kind === 'set_priority') return <>Priority {ref} → <strong>{a.priority}</strong></>;
    if (a.kind === 'set_status')   return <>Status {ref} → <strong>{a.status}</strong></>;
    if (a.kind === 'set_due')      return <>Due date {ref} → <strong>{a.due}</strong></>;
    if (a.kind === 'snooze')       return <>Snooze {ref} until <strong>{a.until}</strong></>;
    if (a.kind === 'add_tag')      return <>Add tag <strong>#{a.tag}</strong> to {ref}</>;
    return <>{a.kind} · {JSON.stringify(a)}</>;
  };
  return (
    <div style={{
      marginTop: 12, padding: 12,
      background: 'rgb(var(--accent-soft) / 0.5)',
      border: '1px solid rgb(var(--accent) / 0.3)',
      borderRadius: 10,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
        <span style={{ fontSize: 11, fontWeight: 700, color: 'rgb(var(--accent-2))', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Suggested actions · {actions.length}</span>
        <span style={{ flex: 1 }} />
        <button onClick={() => actions.forEach((a, i) => !appliedKeys[i] && apply(i, a))} className="btn btn-accent" style={{ fontSize: 11, padding: '3px 10px' }}>Apply all</button>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {actions.map((a, i) => (
          <div key={i} style={{
            display: 'flex', alignItems: 'center', gap: 10,
            padding: '8px 10px',
            background: 'rgb(var(--surface))',
            border: '1px solid rgb(var(--rule))',
            borderRadius: 8,
            opacity: appliedKeys[i] ? 0.55 : 1,
          }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 12.5, color: 'rgb(var(--ink))' }}>{describeAction(a)}</div>
              {a.why && <div style={{ fontSize: 11, color: 'rgb(var(--muted))', marginTop: 2 }}>{a.why}</div>}
            </div>
            {appliedKeys[i]
              ? <span style={{ fontSize: 11, fontWeight: 700, color: 'rgb(var(--forest))' }}>✓ applied</span>
              : <button onClick={() => apply(i, a)} className="btn btn-secondary" style={{ fontSize: 11, padding: '3px 10px' }}>Apply</button>}
          </div>
        ))}
      </div>
    </div>
  );
}

window.PulsePanel = PulsePanel;
