"use client";

import { useEffect, useRef, useState } from "react";
import type { Message } from "./ChatPane";
import type { PersonaInfo } from "./PersonaPicker";

interface ColumnState {
  messages: Message[];
  sessionId: string | null;
  streaming: boolean;
}

interface Props {
  persona: PersonaInfo;
  apiBase: string;
}

type ProviderKey = "anthropic" | "lmstudio";

const PROVIDER_KEYS: ProviderKey[] = ["anthropic", "lmstudio"];

function createEmptyColumn(): ColumnState {
  return { messages: [], sessionId: null, streaming: false };
}

export default function ComparePane({ persona, apiBase }: Props) {
  const [anthropicCol, setAnthropicCol] = useState<ColumnState>(() => createEmptyColumn());
  const [lmstudioCol, setLmstudioCol] = useState<ColumnState>(() => createEmptyColumn());
  const [input, setInput] = useState("");
  const [frontierLabel, setFrontierLabel] = useState("Frontier");
  const [localLabel, setLocalLabel] = useState("Local");
  const anthropicBottomRef = useRef<HTMLDivElement>(null);
  const lmstudioBottomRef = useRef<HTMLDivElement>(null);

  const columns: Record<ProviderKey, ColumnState> = {
    anthropic: anthropicCol,
    lmstudio: lmstudioCol,
  };
  const setColumns: Record<ProviderKey, React.Dispatch<React.SetStateAction<ColumnState>>> = {
    anthropic: setAnthropicCol,
    lmstudio: setLmstudioCol,
  };

  // Fetch provider model ids on mount
  useEffect(() => {
    fetch(`${apiBase}/api/providers`)
      .then((r) => r.json())
      .then((data) => {
        if (data.frontier_model) setFrontierLabel(data.frontier_model);
        if (data.local_model) setLocalLabel(data.local_model);
      })
      .catch(() => {});
  }, [apiBase]);

  // Scroll to bottom on new messages per column
  useEffect(() => {
    if (anthropicCol.messages.length > 0) {
      anthropicBottomRef.current?.scrollIntoView({ behavior: "smooth" });
    }
  }, [anthropicCol.messages]);

  useEffect(() => {
    if (lmstudioCol.messages.length > 0) {
      lmstudioBottomRef.current?.scrollIntoView({ behavior: "smooth" });
    }
  }, [lmstudioCol.messages]);

  const streamColumn = async (
    key: ProviderKey,
    text: string,
    sessionId: string | null,
  ) => {
    const setCol = setColumns[key];

    const assistantMsg: Message = {
      role: "assistant",
      content: "",
      streaming: true,
    };
    setCol((prev) => ({ ...prev, messages: [...prev.messages, assistantMsg] }));

    try {
      const resp = await fetch(`${apiBase}/api/chat/${persona.slug}`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          message: text,
          session_id: sessionId,
          provider: key,
        }),
      });

      if (!resp.ok || !resp.body) {
        throw new Error(`HTTP ${resp.status}`);
      }

      const reader = resp.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });

        const lines = buffer.split("\n");
        buffer = lines.pop() ?? "";

        for (const line of lines) {
          if (!line.startsWith("data: ")) continue;
          const payload = JSON.parse(line.slice(6));
          if (payload.type === "session") {
            setCol((prev) => ({ ...prev, sessionId: payload.session_id }));
          } else if (payload.type === "text") {
            setCol((prev) => {
              const updated = [...prev.messages];
              const last = updated[updated.length - 1];
              if (last.role === "assistant") {
                updated[updated.length - 1] = {
                  ...last,
                  content: last.content + payload.text,
                };
              }
              return { ...prev, messages: updated };
            });
          } else if (payload.type === "done") {
            setCol((prev) => {
              const updated = [...prev.messages];
              const last = updated[updated.length - 1];
              if (last.role === "assistant") {
                updated[updated.length - 1] = { ...last, streaming: false };
              }
              return { ...prev, messages: updated, streaming: false };
            });
          }
        }
      }
    } catch (err) {
      setCol((prev) => {
        const updated = [...prev.messages];
        const last = updated[updated.length - 1];
        if (last.role === "assistant") {
          updated[updated.length - 1] = {
            ...last,
            content: `[Error: ${String(err)}]`,
            streaming: false,
          };
        }
        return { ...prev, messages: updated, streaming: false };
      });
    }
  };

  const sendToBoth = async () => {
    const text = input.trim();
    if (!text) return;
    const isStreaming = anthropicCol.streaming || lmstudioCol.streaming;
    if (isStreaming) return;
    setInput("");

    const userMsg: Message = { role: "user", content: text };

    for (const key of PROVIDER_KEYS) {
      const setCol = setColumns[key];
      setCol((prev) => ({
        ...prev,
        messages: [...prev.messages, userMsg],
        streaming: true,
      }));
    }

    await Promise.all(
      PROVIDER_KEYS.map((key) =>
        streamColumn(key, text, columns[key].sessionId),
      ),
    );
  };

  const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      sendToBoth();
    }
  };

  const isStreaming = anthropicCol.streaming || lmstudioCol.streaming;

  const columnLabels: Record<ProviderKey, string> = {
    anthropic: frontierLabel,
    lmstudio: localLabel,
  };

  return (
    <div style={styles.container}>
      <div style={styles.columns}>
        {PROVIDER_KEYS.map((key) => {
          const col = columns[key];
          const bottomRef =
            key === "anthropic" ? anthropicBottomRef : lmstudioBottomRef;
          return (
            <div key={key} style={styles.column}>
              <div style={styles.header}>
                <span style={styles.headerName}>
                  {columnLabels[key]}
                </span>
                <span style={styles.headerMeta}>
                  {key === "anthropic" ? "frontier" : "local"}
                </span>
              </div>
              <div style={styles.messages}>
                {col.messages.length === 0 && (
                  <div style={styles.empty}>
                    Send a message to compare {columnLabels[key]}.
                  </div>
                )}
                {col.messages.map((msg, i) => (
                  <div
                    key={i}
                    style={{
                      ...styles.bubble,
                      ...(msg.role === "user"
                        ? styles.userBubble
                        : styles.assistantBubble),
                    }}
                  >
                    <span style={styles.role}>
                      {msg.role === "user"
                        ? "You"
                        : persona.display_name}
                    </span>
                    <p style={styles.text}>
                      {msg.content}
                      {msg.streaming && (
                        <span style={styles.cursor}>▌</span>
                      )}
                    </p>
                  </div>
                ))}
                <div ref={bottomRef} />
              </div>
            </div>
          );
        })}
      </div>
      <div style={styles.inputRow}>
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={onKeyDown}
          placeholder={`Ask ${persona.display_name} something…`}
          disabled={isStreaming}
          rows={2}
          style={styles.textarea}
        />
        <button
          onClick={sendToBoth}
          disabled={isStreaming || !input.trim()}
          style={{
            ...styles.sendBtn,
            ...(isStreaming || !input.trim() ? styles.sendBtnDisabled : {}),
          }}
        >
          Send to both
        </button>
      </div>
    </div>
  );
}

const styles: Record<string, React.CSSProperties> = {
  container: {
    display: "flex",
    flexDirection: "column",
    height: "100%",
    background: "var(--bg)",
  },
  columns: {
    flex: 1,
    display: "flex",
    gap: "1px",
    overflow: "hidden",
    borderBottom: "1px solid var(--border)",
  },
  column: {
    flex: 1,
    display: "flex",
    flexDirection: "column",
    overflow: "hidden",
    background: "var(--surface)",
  },
  header: {
    padding: "14px 16px",
    borderBottom: "1px solid var(--border)",
    display: "flex",
    alignItems: "baseline",
    gap: "10px",
    background: "var(--surface)",
    flexShrink: 0,
  },
  headerName: {
    fontWeight: 700,
    color: "var(--accent)",
    fontSize: "14px",
  },
  headerMeta: {
    color: "var(--text-muted)",
    fontSize: "12px",
  },
  messages: {
    flex: 1,
    overflowY: "auto",
    padding: "16px",
    display: "flex",
    flexDirection: "column",
    gap: "12px",
  },
  empty: {
    color: "var(--text-muted)",
    fontStyle: "italic",
    textAlign: "center",
    marginTop: "40px",
    fontSize: "13px",
  },
  bubble: {
    display: "flex",
    flexDirection: "column",
    gap: "4px",
  },
  userBubble: {
    alignSelf: "flex-end",
    alignItems: "flex-end",
  },
  assistantBubble: {
    alignSelf: "flex-start",
    alignItems: "flex-start",
  },
  role: {
    fontSize: "11px",
    color: "var(--text-muted)",
    fontWeight: 600,
    textTransform: "uppercase",
    letterSpacing: "0.05em",
  },
  text: {
    background: "var(--bg)",
    padding: "8px 12px",
    borderRadius: "var(--radius)",
    lineHeight: 1.65,
    fontSize: "13px",
    border: "1px solid var(--border)",
    whiteSpace: "pre-wrap",
  },
  cursor: {
    animation: "blink 1s step-end infinite",
    color: "var(--accent)",
  },
  inputRow: {
    display: "flex",
    gap: "8px",
    padding: "14px 16px",
    borderTop: "1px solid var(--border)",
    background: "var(--surface)",
    flexShrink: 0,
  },
  textarea: {
    flex: 1,
    padding: "10px 14px",
    borderRadius: "var(--radius)",
    border: "1px solid var(--border)",
    background: "var(--bg)",
    color: "var(--text)",
    resize: "none",
    outline: "none",
  },
  sendBtn: {
    padding: "0 20px",
    background: "var(--accent)",
    color: "#000",
    borderRadius: "var(--radius)",
    fontWeight: 600,
    fontSize: "13px",
    transition: "opacity 0.15s",
    whiteSpace: "nowrap",
  },
  sendBtnDisabled: {
    opacity: 0.4,
    cursor: "default",
  },
};
