// Chat view — session conversation

function ChatView({ theme, session, machine, onBack, onDeleted }) {
  const t = theme;
  const store = useStore();
  const scrollRef = React.useRef(null);
  const [input, setInput] = React.useState("");
  const [showMenu, setShowMenu] = React.useState(false);
  const [renaming, setRenaming] = React.useState(false);
  const [renameVal, setRenameVal] = React.useState(session.name || "");
  const [confirmDelete, setConfirmDelete] = React.useState(false);
  const msgs = store.messages[session.id] || [];
  const blocks = store.streamBlocks[session.id] || [];
  const isRunning = session.status === "running" || (store.sessionStatus[session.id] === "running");

  React.useEffect(() => {
    store.subscribe(session.id);
    return () => store.unsubscribe(session.id);
  }, [session.id]);

  React.useEffect(() => {
    if (scrollRef.current) {
      const el = scrollRef.current;
      el.scrollTop = el.scrollHeight;
    }
  }, [msgs.length, blocks.length]);

  const handleSend = () => {
    const text = input.trim();
    if (!text) return;
    store.sendMessage(session.id, text);
    setInput("");
  };

  const handleKeyDown = (e) => {
    if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSend(); }
  };

  const title = session.name || session.agent_type || "Session";

  return (
    <main style={{ flex: 1, display: "flex", flexDirection: "column", background: t.chatBg, fontFamily: t.fontSans, color: t.fg, minWidth: 0 }}>
      {/* Header */}
      <div style={{ padding: "14px 28px", borderBottom: `1px solid ${t.line}`, display: "flex", alignItems: "center", gap: 16, background: t.bg2 }}>
        <div style={{ flex: 1 }}>
          {renaming ? (
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <input value={renameVal} onChange={e => setRenameVal(e.target.value)}
                onKeyDown={e => { if (e.key === "Enter") { store.renameSession(session.id, renameVal); setRenaming(false); } if (e.key === "Escape") setRenaming(false); }}
                autoFocus style={{ padding: "4px 8px", background: t.panel2, border: `1px solid ${t.line2}`, borderRadius: t.radius, color: t.fg, fontFamily: t.fontDisplay, fontSize: 15, fontWeight: t.weightHeading, outline: "none", width: 200 }} />
              <button onClick={() => { store.renameSession(session.id, renameVal); setRenaming(false); }} style={{ padding: "4px 10px", background: t.accent, color: t.bg, border: "none", borderRadius: t.radius, cursor: "pointer", fontSize: 11 }}>Save</button>
              <button onClick={() => setRenaming(false)} style={{ padding: "4px 10px", background: "transparent", border: `1px solid ${t.line2}`, borderRadius: t.radius, color: t.fg2, cursor: "pointer", fontSize: 11 }}>Cancel</button>
            </div>
          ) : (
            <>
              <div style={{ fontFamily: t.fontDisplay, fontWeight: t.weightHeading, fontSize: 15, color: t.fg, lineHeight: 1.1 }}>{title}</div>
              <div style={{ fontSize: 11, fontFamily: t.fontMono, color: t.fg3, marginTop: 3, display: "flex", gap: 10, alignItems: "center" }}>
                {machine && <span style={{ display: "flex", alignItems: "center", gap: 5 }}>
                  <StatusDot status={machine.status} theme={t} /> {machine.name}
                </span>}
                <span style={{ opacity: 0.6 }}>-</span>
                <span>{session.agent_type}</span>
              </div>
            </>
          )}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 11, fontFamily: t.fontMono, color: t.fg2 }}>
          <StatusDot status={isRunning ? "running" : session.status} theme={t} />
          <span style={{ textTransform: "uppercase", letterSpacing: 0.8 }}>{isRunning ? "running" : session.status}</span>
          {isRunning && <button onClick={() => store.stopSession(session.id)} style={{
            padding: "4px 10px", background: t.err, color: "#fff", border: "none",
            borderRadius: t.radius, cursor: "pointer", fontSize: 11, fontFamily: t.fontMono,
          }}>Stop</button>}
          <div style={{ position: "relative" }}>
            <button onClick={() => setShowMenu(!showMenu)} style={{ ...iconBtn(t), width: 24, height: 24 }} title="Actions">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg>
            </button>
            {showMenu && <ChatMenu theme={t} onRename={() => { setRenameVal(session.name || ""); setRenaming(true); setShowMenu(false); }}
              onArchive={() => { store.archiveSession(session.id); setShowMenu(false); if (onBack) onBack(); }}
              onDelete={() => { setConfirmDelete(true); setShowMenu(false); }}
              onClose={() => setShowMenu(false)} />}
          </div>
        </div>
      </div>
      {confirmDelete && <ConfirmDeleteModal theme={t} name={title}
        onConfirm={() => { store.deleteSession(session.id); setConfirmDelete(false); if (onDeleted) onDeleted(); }}
        onCancel={() => setConfirmDelete(false)} />}

      {/* Messages */}
      <div ref={scrollRef} style={{ flex: 1, overflowY: "auto", padding: "28px 0 20px" }}>
        <div style={{ maxWidth: 780, margin: "0 auto", padding: "0 28px" }}>
          {msgs.map((m, i) => <MessageBubble key={m.client_message_id || i} m={m} theme={t} />)}
          {blocks.length > 0 && <StreamingBlocks blocks={blocks} theme={t} />}
          {isRunning && blocks.length === 0 && <ThinkingDots theme={t} />}
        </div>
      </div>

      {/* Composer */}
      <div style={{ borderTop: `1px solid ${t.line}`, padding: "14px 28px 18px", background: t.bg2 }}>
        <div style={{ maxWidth: 780, margin: "0 auto" }}>
          <div style={{
            background: t.panel, border: `1px solid ${t.line2}`, borderRadius: t.radius * 2,
            padding: "10px 14px", display: "flex", alignItems: "flex-end", gap: 10, minHeight: 48,
          }}>
            <textarea
              value={input} onChange={e => setInput(e.target.value)} onKeyDown={handleKeyDown}
              placeholder="Message the agent..." rows={1}
              disabled={isRunning}
              style={{
                flex: 1, background: "transparent", border: "none", outline: "none", resize: "none",
                color: t.fg, fontFamily: t.fontSans, fontSize: 13.5, lineHeight: 1.5, padding: "6px 0", minHeight: 22,
              }}
            />
            <div style={{ display: "flex", alignItems: "center", gap: 8, paddingBottom: 4 }}>
              <span style={{ fontSize: 10, fontFamily: t.fontMono, color: t.fg3 }}>Enter</span>
              <button onClick={handleSend} disabled={isRunning || !input.trim()} style={{
                width: 30, height: 30, borderRadius: t.radius + 2,
                background: input.trim() && !isRunning ? t.accent : t.panel2,
                color: input.trim() && !isRunning ? t.bg : t.fg3,
                border: `1px solid ${input.trim() && !isRunning ? t.accent : t.line2}`,
                display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer",
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/></svg>
              </button>
            </div>
          </div>
        </div>
      </div>
    </main>
  );
}

function MessageBubble({ m, theme }) {
  const t = theme;
  const isUser = m.sender_type === "user";
  const content = parseContent(m.content_encrypted || m.content || "");
  const time = m.created_at ? new Date(m.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : "";

  if (isUser) {
    return (
      <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 18 }}>
        <div style={{ maxWidth: "70%" }}>
          <div style={{
            background: t.user, color: t.userFg, padding: "10px 14px",
            borderRadius: t.radius * 2, borderTopRightRadius: t.radius / 2,
            fontSize: 13.5, lineHeight: 1.5, whiteSpace: "pre-wrap",
          }}>{content.text}</div>
          <div style={{ fontSize: 10, fontFamily: t.fontMono, color: t.fg3, marginTop: 4, textAlign: "right" }}>{time}</div>
        </div>
      </div>
    );
  }

  return (
    <div style={{ display: "flex", gap: 12, marginBottom: 22, alignItems: "flex-start" }}>
      <div style={{
        width: 26, height: 26, borderRadius: t.radius + 2, background: t.panel, border: `1px solid ${t.line2}`,
        display: "flex", alignItems: "center", justifyContent: "center",
        color: t.accent, fontFamily: t.fontMono, fontSize: 12, fontWeight: 700, flexShrink: 0, marginTop: 2,
      }}>*</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        {content.toolCalls && content.toolCalls.length > 0 && (
          <CollapsedToolCalls toolCalls={content.toolCalls} theme={t} />
        )}
        <div style={{ fontSize: 13.5, lineHeight: 1.6, color: t.fg }}
          dangerouslySetInnerHTML={{ __html: renderMd(content.text) }} />
        <div style={{ fontSize: 10, fontFamily: t.fontMono, color: t.fg3, marginTop: 6 }}>{time}</div>
      </div>
    </div>
  );
}

function CollapsedToolCalls({ toolCalls, theme }) {
  const t = theme;
  const [expanded, setExpanded] = React.useState(false);
  const MAX_VISIBLE = 3;
  const hiddenCount = toolCalls.length - MAX_VISIBLE;
  const visible = expanded ? toolCalls : toolCalls.slice(-MAX_VISIBLE);

  return (
    <div>
      {hiddenCount > 0 && (
        <button onClick={() => setExpanded(!expanded)} style={{
          display: "inline-flex", alignItems: "center", gap: 6,
          padding: "3px 10px", marginBottom: 6,
          background: t.panel2, border: `1px solid ${t.line}`,
          borderRadius: 999, color: t.fg3, fontFamily: t.fontMono, fontSize: 10.5,
          cursor: "pointer",
        }}>
          {expanded ? `Collapse ${hiddenCount} tool call${hiddenCount > 1 ? "s" : ""}` : `+${hiddenCount} tool call${hiddenCount > 1 ? "s" : ""}`}
          <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ transform: expanded ? "rotate(180deg)" : "rotate(0deg)", transition: "transform 0.15s" }}>
            <polyline points="6 9 12 15 18 9"/>
          </svg>
        </button>
      )}
      {visible.map((tc, i) => <ToolCallBlock key={i} tc={tc} theme={t} />)}
    </div>
  );
}

function ToolCallBlock({ tc, theme }) {
  const t = theme;
  const [open, setOpen] = React.useState(false);
  const ok = !tc.is_error;
  return (
    <div style={{ marginBottom: 6 }}>
      <button onClick={() => setOpen(!open)} style={{
        display: "inline-flex", alignItems: "center", gap: 8,
        padding: "4px 10px 4px 8px", background: t.panel, border: `1px solid ${t.line}`,
        borderRadius: 999, color: t.fg2, fontFamily: t.fontMono, fontSize: 11, cursor: "pointer", maxWidth: "100%",
      }}>
        <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ transform: open ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.15s" }}>
          <polyline points="9 18 15 12 9 6"/>
        </svg>
        <span style={{ width: 5, height: 5, borderRadius: 999, background: ok ? t.accent : t.err, display: "inline-block" }} />
        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 300 }}>{tc.tool || tc.name || "tool"}</span>
      </button>
      {open && (
        <div style={{
          marginTop: 6, padding: "10px 12px", background: t.panel2, border: `1px solid ${t.line}`,
          borderLeft: `2px solid ${ok ? t.accent : t.err}`, borderRadius: t.radius,
          fontFamily: t.fontMono, fontSize: 11, color: t.fg2, whiteSpace: "pre-wrap", lineHeight: 1.5, maxHeight: 200, overflowY: "auto",
        }}>{typeof tc.output === "string" ? tc.output : typeof tc.input === "string" ? tc.input : JSON.stringify(tc.output || tc.input || tc, null, 2)}</div>
      )}
    </div>
  );
}

function StreamingBlocks({ blocks, theme }) {
  const t = theme;
  const [expanded, setExpanded] = React.useState(false);
  const visibleTools = blocks.filter(b => b.type === "tool_use" || b.type === "tool_result");
  const textBlocks = blocks.filter(b => b.type === "text");
  const lastText = textBlocks.length > 0 ? textBlocks.map(b => b.text || "").join("") : "";
  const MAX_VISIBLE = 3;
  const hiddenCount = visibleTools.length - MAX_VISIBLE;
  const showTools = expanded ? visibleTools : visibleTools.slice(-MAX_VISIBLE);

  return (
    <div style={{ display: "flex", gap: 12, marginBottom: 22, alignItems: "flex-start" }}>
      <div style={{
        width: 26, height: 26, borderRadius: t.radius + 2, background: t.panel, border: `1px solid ${t.line2}`,
        display: "flex", alignItems: "center", justifyContent: "center",
        color: t.accent, fontFamily: t.fontMono, fontSize: 12, fontWeight: 700, flexShrink: 0, marginTop: 2,
      }}>*</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        {hiddenCount > 0 && (
          <button onClick={() => setExpanded(!expanded)} style={{
            display: "inline-flex", alignItems: "center", gap: 6,
            padding: "3px 10px", marginBottom: 6,
            background: t.panel2, border: `1px solid ${t.line}`,
            borderRadius: 999, color: t.fg3, fontFamily: t.fontMono, fontSize: 10.5,
            cursor: "pointer",
          }}>
            {expanded ? `Collapse ${hiddenCount} tool call${hiddenCount > 1 ? "s" : ""}` : `+${hiddenCount} tool call${hiddenCount > 1 ? "s" : ""}`}
            <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ transform: expanded ? "rotate(180deg)" : "rotate(0deg)", transition: "transform 0.15s" }}>
              <polyline points="6 9 12 15 18 9"/>
            </svg>
          </button>
        )}
        {showTools.map((tc, i) => <ToolCallBlock key={i} tc={tc} theme={t} />)}
        {lastText && <div style={{ fontSize: 13.5, lineHeight: 1.6, color: t.fg }}
          dangerouslySetInnerHTML={{ __html: renderMd(lastText) }} />}
        <ThinkingDots theme={t} />
      </div>
    </div>
  );
}

function ThinkingDots({ theme }) {
  const t = theme;
  return (
    <div style={{ display: "flex", gap: 4, padding: "8px 0" }}>
      {[0,1,2].map(i => <span key={i} style={{
        width: 6, height: 6, borderRadius: 999, background: t.accent,
        animation: `ac-bounce 1.2s ${i * 0.15}s infinite ease-in-out`,
      }} />)}
    </div>
  );
}

function parseContent(raw) {
  if (!raw) return { text: "", toolCalls: [] };
  try {
    const parsed = JSON.parse(raw);
    if (parsed.blocks) {
      const text = parsed.blocks.filter(b => b.type === "text").map(b => {
        const v = b.text || b.content || "";
        return typeof v === "string" ? v : JSON.stringify(v);
      }).join("\n");
      const toolCalls = parsed.blocks.filter(b => b.type === "tool_use" || b.type === "tool_result");
      return { text: text || parsed.text || "", toolCalls };
    }
    if (parsed.text) return { text: parsed.text, toolCalls: [] };
  } catch {}
  return { text: raw, toolCalls: [] };
}

function renderMd(text) {
  if (!text) return "";
  // Escape HTML
  let html = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  // Code blocks (triple backtick)
  html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
    return `<pre style="background:rgba(128,128,128,0.1);padding:12px;border-radius:4px;overflow-x:auto;font-size:12px;line-height:1.5;margin:8px 0"><code>${code.trim()}</code></pre>`;
  });
  // Tables — detect lines with pipes
  html = html.replace(/((?:^\|.+\|[ ]*$\n?)+)/gm, (tableBlock) => {
    const rows = tableBlock.trim().split("\n").filter(r => r.trim());
    if (rows.length < 2) return tableBlock;
    // Check if 2nd row is separator (|---|---|)
    const isSep = /^\|[\s\-:|]+\|$/.test(rows[1].trim());
    const dataRows = isSep ? [rows[0], ...rows.slice(2)] : rows;
    const parseRow = r => r.replace(/^\|/, "").replace(/\|$/, "").split("|").map(c => c.trim());
    const headerCells = parseRow(dataRows[0]);
    const bodyRows = dataRows.slice(1);
    let tbl = '<table style="border-collapse:collapse;margin:8px 0;font-size:12.5px;width:100%;overflow-x:auto">';
    tbl += "<thead><tr>";
    headerCells.forEach(c => { tbl += `<th style="border:1px solid rgba(128,128,128,0.3);padding:6px 10px;text-align:left;font-weight:600">${c}</th>`; });
    tbl += "</tr></thead><tbody>";
    bodyRows.forEach(r => {
      const cells = parseRow(r);
      tbl += "<tr>";
      cells.forEach(c => { tbl += `<td style="border:1px solid rgba(128,128,128,0.2);padding:5px 10px">${c}</td>`; });
      tbl += "</tr>";
    });
    tbl += "</tbody></table>";
    return tbl;
  });
  // Inline code
  html = html.replace(/`([^`]+)`/g, '<code style="background:rgba(128,128,128,0.15);padding:1px 4px;border-radius:3px;font-size:12px">$1</code>');
  // Bold
  html = html.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
  // Italic
  html = html.replace(/\*(.+?)\*/g, "<em>$1</em>");
  // Headers
  html = html.replace(/^### (.+)$/gm, '<div style="font-size:14px;font-weight:600;margin:12px 0 4px">$1</div>');
  html = html.replace(/^## (.+)$/gm, '<div style="font-size:15px;font-weight:600;margin:14px 0 6px">$1</div>');
  html = html.replace(/^# (.+)$/gm, '<div style="font-size:17px;font-weight:700;margin:16px 0 8px">$1</div>');
  // Unordered lists
  html = html.replace(/^- (.+)$/gm, '<div style="padding-left:16px;margin:2px 0">&#x2022; $1</div>');
  // Ordered lists
  html = html.replace(/^(\d+)\. (.+)$/gm, '<div style="padding-left:16px;margin:2px 0">$1. $2</div>');
  // Links
  html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" style="color:inherit;text-decoration:underline">$1</a>');
  // Collapse 3+ consecutive newlines into a double break, then convert remaining
  html = html.replace(/\n{3,}/g, "\n\n");
  // Double newline = paragraph break
  html = html.replace(/\n\n(?!<\/?(pre|code|div|table|thead|tbody|tr|th|td))/g, '<div style="margin:8px 0"></div>');
  // Single newline = line break (but not after block elements)
  html = html.replace(/\n(?!<\/?(pre|code|div|table|thead|tbody|tr|th|td))/g, "<br>");
  return html;
}

function ChatMenu({ theme, onRename, onArchive, onDelete, onClose }) {
  const t = theme;
  const ref = React.useRef(null);
  React.useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  const itemStyle = { width: "100%", display: "flex", alignItems: "center", gap: 8, padding: "8px 12px", background: "transparent", border: "none", borderRadius: t.radius - 2, color: t.fg, cursor: "pointer", fontFamily: t.fontSans, fontSize: 12, textAlign: "left" };
  return (
    <div ref={ref} style={{ position: "absolute", top: 30, right: 0, width: 160, background: t.panel, border: `1px solid ${t.line2}`, borderRadius: t.radius, padding: 4, boxShadow: "0 8px 24px rgba(0,0,0,0.3)", zIndex: 100, animation: "ac-fade 0.15s" }}>
      <button onClick={onRename} style={itemStyle} onMouseEnter={e => e.currentTarget.style.background = t.panel2} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
        Rename
      </button>
      <button onClick={onArchive} style={itemStyle} onMouseEnter={e => e.currentTarget.style.background = t.panel2} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="21 8 21 21 3 21 3 8"/><rect x="1" y="3" width="22" height="5"/><line x1="10" y1="12" x2="14" y2="12"/></svg>
        Archive
      </button>
      <div style={{ height: 1, background: t.line, margin: "4px 0" }} />
      <button onClick={onDelete} style={{ ...itemStyle, color: t.err }} onMouseEnter={e => e.currentTarget.style.background = t.panel2} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
        Delete
      </button>
    </div>
  );
}

function ConfirmDeleteModal({ theme, name, onConfirm, onCancel }) {
  const t = theme;
  return (
    <div onClick={onCancel} style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 200 }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 360, background: t.panel, border: `1px solid ${t.line2}`, borderRadius: t.radius + 4, padding: 24, fontFamily: t.fontSans, color: t.fg, animation: "ac-fade 0.2s" }}>
        <div style={{ fontFamily: t.fontDisplay, fontWeight: t.weightHeading, fontSize: 16, marginBottom: 12 }}>Delete session</div>
        <div style={{ fontSize: 13, color: t.fg2, lineHeight: 1.5, marginBottom: 20 }}>Are you sure you want to delete <strong>{name}</strong>? This will permanently remove the session and all its messages.</div>
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button onClick={onCancel} style={{ padding: "8px 16px", background: "transparent", border: `1px solid ${t.line2}`, borderRadius: t.radius, color: t.fg2, cursor: "pointer", fontSize: 13 }}>Cancel</button>
          <button onClick={onConfirm} style={{ padding: "8px 16px", background: t.err, color: "#fff", border: "none", borderRadius: t.radius, cursor: "pointer", fontSize: 13, fontWeight: 600 }}>Delete</button>
        </div>
      </div>
    </div>
  );
}

window.ChatView = ChatView;
