/* ============================================================
   claude-chat.jsx — окно общения с Claude внутри Планера.
   Доступно только на машине разработки (/api/claude/available).
   Claude запускается на сервере (Claude Code CLI) и опирается
   на «второй мозг» проекта в Obsidian.
   ============================================================ */
(() => {
const React = window.React;
const { useState, useEffect, useRef } = React;

const LS_SESSION = "planer-claude-session";
const LS_HISTORY = "planer-claude-history";

function loadHistory() {
  try {
    const h = JSON.parse(localStorage.getItem(LS_HISTORY));
    if (Array.isArray(h)) return h.slice(-200);
  } catch (e) {}
  return [];
}

function saveHistory(msgs) {
  try { localStorage.setItem(LS_HISTORY, JSON.stringify(msgs.slice(-200))); } catch (e) {}
}

/* лёгкий рендер: абзацы + блоки кода ``` */
function MsgText({ text }) {
  const parts = String(text).split(/```[a-zA-Z]*\n?/);
  return (
    <>
      {parts.map((p, i) =>
        i % 2 === 1
          ? <pre key={i} className="cchat-code">{p.replace(/\n$/, "")}</pre>
          : (p.trim() ? <span key={i}>{p}</span> : null)
      )}
    </>
  );
}

function ClaudeChat() {
  const [available, setAvailable] = useState(false);
  const [open, setOpen] = useState(false);
  const [messages, setMessages] = useState(loadHistory);
  const [input, setInput] = useState("");
  const [busy, setBusy] = useState(false);
  const [status, setStatus] = useState(null);
  const sessionRef = useRef(localStorage.getItem(LS_SESSION) || null);
  const abortRef = useRef(null);
  const listRef = useRef(null);

  useEffect(() => {
    window.authFetch("/api/claude/available")
      .then((r) => r.json())
      .then((d) => setAvailable(!!d.available))
      .catch(() => {});
  }, []);

  useEffect(() => { saveHistory(messages); }, [messages]);

  useEffect(() => {
    const el = listRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, status, open]);

  const push = (msg) => setMessages((m) => [...m, msg]);

  const handleEvent = (ev) => {
    if (ev.type === "session") {
      sessionRef.current = ev.sessionId;
      try { localStorage.setItem(LS_SESSION, ev.sessionId); } catch (e) {}
    } else if (ev.type === "text") {
      push({ role: "assistant", text: ev.text });
      setStatus(null);
    } else if (ev.type === "tool") {
      const line = ev.name + (ev.detail ? " · " + ev.detail : "");
      push({ role: "tool", text: line });
      setStatus(line);
    } else if (ev.type === "done") {
      if (!ev.ok && ev.error) push({ role: "error", text: ev.error });
      if (ev.filesChanged) push({ role: "reload" });
    } else if (ev.type === "error") {
      push({ role: "error", text: ev.error });
    }
  };

  const send = async () => {
    const text = input.trim();
    if (!text || busy) return;
    setInput("");
    push({ role: "user", text });
    setBusy(true);
    setStatus("Claude думает…");
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    try {
      const res = await window.authFetch("/api/claude/message", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ prompt: text, sessionId: sessionRef.current }),
        signal: ctrl.signal,
      });
      if (!res.ok || !res.body) {
        const d = await res.json().catch(() => ({}));
        throw new Error(d.error || "HTTP " + res.status);
      }
      const reader = res.body.getReader();
      const dec = new TextDecoder();
      let buf = "";
      for (;;) {
        const { done, value } = await reader.read();
        if (done) break;
        buf += dec.decode(value, { stream: true });
        const chunks = buf.split("\n\n");
        buf = chunks.pop();
        for (const chunk of chunks) {
          const line = chunk.split("\n").find((l) => l.startsWith("data: "));
          if (!line) continue;
          try { handleEvent(JSON.parse(line.slice(6))); } catch (e) {}
        }
      }
    } catch (err) {
      if (err.name === "AbortError") push({ role: "tool", text: "Остановлено" });
      else push({ role: "error", text: err.message });
    } finally {
      setBusy(false);
      setStatus(null);
      abortRef.current = null;
    }
  };

  const stop = () => { if (abortRef.current) abortRef.current.abort(); };

  const newDialog = () => {
    if (busy) stop();
    sessionRef.current = null;
    try { localStorage.removeItem(LS_SESSION); } catch (e) {}
    setMessages([]);
  };

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

  if (!available) return null;

  if (!open) {
    return (
      <button className="cchat-fab" title="Claude — разработка" onClick={() => setOpen(true)}>
        ✦
      </button>
    );
  }

  return (
    <div className="cchat">
      <div className="cchat-head">
        <span className="cchat-title">CLAUDE · РАЗРАБОТКА</span>
        <span className="cchat-session">{sessionRef.current ? "сессия продолжается" : "новая сессия"}</span>
        <button className="cchat-hbtn" title="Новый диалог" onClick={newDialog}>⟳</button>
        <button className="cchat-hbtn" title="Свернуть" onClick={() => setOpen(false)}>—</button>
      </div>

      <div className="cchat-list" ref={listRef}>
        {messages.length === 0 && (
          <div className="cchat-empty">
            Опиши изменение, которое нужно внести в Планер.<br />
            Claude прочитает «второй мозг» проекта и внесёт правки в код.
          </div>
        )}
        {messages.map((m, i) => {
          if (m.role === "reload") {
            return (
              <div key={i} className="cchat-reload">
                Файлы проекта изменены.
                <button onClick={() => window.location.reload(true)}>Обновить страницу</button>
              </div>
            );
          }
          return (
            <div key={i} className={"cchat-msg cchat-msg--" + m.role}>
              <MsgText text={m.text} />
            </div>
          );
        })}
        {busy && <div className="cchat-status">{status || "…"}<span className="cchat-blink">▊</span></div>}
      </div>

      <div className="cchat-input">
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={onKey}
          placeholder="Что изменить в Планере?"
          rows={2}
          disabled={busy}
        />
        {busy
          ? <button className="cchat-send cchat-send--stop" onClick={stop}>Стоп</button>
          : <button className="cchat-send" onClick={send} disabled={!input.trim()}>→</button>}
      </div>
    </div>
  );
}

window.ClaudeChat = ClaudeChat;
})();
