import { useState, useRef, useEffect, type KeyboardEvent } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { Tooltip } from "./Tooltip";
import { Send, Square, Plus, X, Sparkles, Loader } from "lucide-react";
import type { UIMessage } from "ai";
import { isToolPart, normalizeToolPart } from "../utils/ai-tool-parts";

export interface ModelOption {
  id: string;
  label: string;
  context: string;
  cost: string;
}

interface ChatPanelProps {
  messages: UIMessage[];
  isLoading: boolean;
  error: Error | undefined;
  input: string;
  models: ModelOption[];
  selectedModel: string;
  onModelChange: (modelId: string) => void;
  onSend: (content: string) => void;
  onSetInput: (value: string) => void;
  onStop: () => void;
  onNewChat: () => void;
  onClose?: () => void;
}

function TokenGauge({ tokens, ratio }: { tokens: number; ratio: number }) {
  const r = 8;
  const circ = 2 * Math.PI * r;
  const offset = circ * (1 - ratio);
  const color = ratio > 0.8 ? "var(--ed-error)" : ratio > 0.5 ? "#ff9800" : "var(--ed-text-disabled)";
  const label = tokens < 1000 ? `${tokens}` : `${(tokens / 1000).toFixed(1)}k`;

  if (tokens === 0) return null;

  return (
    <Tooltip title={`~${label} tokens used`}>
      <div className="token-gauge" style={{ display: "inline-flex", alignItems: "center", cursor: "default" }}>
        <svg width="18" height="18" viewBox="0 0 20 20" style={{ transform: "rotate(-90deg)" }}>
          <circle cx="10" cy="10" r={r} fill="none" stroke="var(--ed-border)" strokeWidth="2" />
          <circle
            cx="10" cy="10" r={r}
            fill="none" stroke={color} strokeWidth="2"
            strokeDasharray={circ}
            strokeDashoffset={offset}
            strokeLinecap="round"
            style={{ transition: "stroke-dashoffset 300ms ease, stroke 300ms ease" }}
          />
        </svg>
      </div>
    </Tooltip>
  );
}

export function ChatPanel({
  messages,
  isLoading,
  error,
  input,
  models,
  selectedModel,
  onModelChange,
  onSend,
  onSetInput,
  onStop,
  onNewChat,
  onClose,
}: ChatPanelProps) {
  const scrollRef = useRef<HTMLDivElement>(null);

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

  const inputValue = input ?? "";

  const handleSubmit = () => {
    if (!inputValue.trim() || isLoading) return;
    onSend(inputValue.trim());
    onSetInput("");
  };

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

  const estimatedTokens = messages.reduce((sum, msg) => {
    const text = msg.parts
      ?.filter((p) => p.type === "text")
      .map((p) => (p as { type: "text"; text: string }).text)
      .join("") ?? "";
    return sum + Math.ceil(text.length / 4);
  }, 0);

  const selectedModelInfo = models.find((m) => m.id === selectedModel);
  const contextLimit = selectedModelInfo
    ? parseFloat(selectedModelInfo.context) * 1000
    : 200_000;
  const usageRatio = Math.min(estimatedTokens / contextLimit, 1);

  return (
    <div className="chat-panel">
      {/* Header */}
      <div className="chat-panel__header">
        <span className="chat-panel__label">AI Assistant</span>
        <div className="chat-panel__header-right">
          <TokenGauge tokens={estimatedTokens} ratio={usageRatio} />
          {models.length > 0 && (
            <select
              className="chat-panel__model-select"
              value={selectedModel}
              onChange={(e) => onModelChange(e.target.value)}
            >
              {models.map((m) => (
                <option key={m.id} value={m.id}>
                  {m.label} ({m.context}) {m.cost}
                </option>
              ))}
            </select>
          )}
          <Tooltip title="New conversation">
            <button className="icon-btn icon-btn--sm" onClick={onNewChat} aria-label="New conversation">
              <Plus size={14} />
            </button>
          </Tooltip>
          {onClose && (
            <button className="icon-btn icon-btn--sm" onClick={onClose} aria-label="Close chat">
              <X size={14} />
            </button>
          )}
        </div>
      </div>

      {/* Messages */}
      <div ref={scrollRef} className="chat-panel__messages">
        {messages.length === 0 && (
          <div className="chat-panel__empty">
            Ask me to write, edit, expand, or improve your article.
          </div>
        )}

        {messages.map((msg) => (
          <MessageBubble key={msg.id} message={msg} />
        ))}

        {isLoading && messages.length > 0 && (
          <AgentStatus messages={messages} />
        )}

        {error && (
          <div className="chat-panel__error">
            {error.message}
          </div>
        )}
      </div>

      {/* Input */}
      <div className="chat-panel__input">
        <div className="chat-panel__input-row">
          <textarea
            className="chat-panel__textarea"
            rows={1}
            placeholder="Ask anything..."
            value={inputValue}
            onChange={(e) => onSetInput(e.target.value)}
            onKeyDown={handleKeyDown}
          />
          {isLoading ? (
            <button className="icon-btn" onClick={onStop} aria-label="Stop" style={{ color: "#ff9800", flexShrink: 0 }}>
              <Square size={18} />
            </button>
          ) : (
            <button
              className="icon-btn"
              onClick={handleSubmit}
              disabled={!inputValue.trim()}
              aria-label="Send"
              style={{ color: inputValue.trim() ? "var(--primary-color)" : "var(--ed-text-disabled)", flexShrink: 0 }}
            >
              <Send size={18} />
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function MessageBubble({ message }: { message: UIMessage }) {
  const isUser = message.role === "user";

  const parts = message.parts ?? [];
  const textParts = parts.filter((p) => p.type === "text");
  const toolParts = parts.filter(isToolPart);
  const textContent = textParts.length > 0
    ? textParts.map((p) => (p as { type: "text"; text: string }).text).join("")
    : (message as any).content ?? "";

  if (!textContent && message.role === "assistant" && toolParts.length === 0) return null;

  return (
    <div className="chat-bubble">
      {textContent && (
        <div className={`chat-bubble__text ${isUser ? "chat-bubble__text--user" : ""}`}>
          {isUser ? textContent : (
            <ReactMarkdown remarkPlugins={[remarkGfm]}>{textContent}</ReactMarkdown>
          )}
        </div>
      )}

      {toolParts.map((part, i) => {
        const tool = normalizeToolPart(part);
        if (!tool) return null;
        return (
          <div key={i} className="chat-bubble__tool">
            <Sparkles size={12} />
            <span>{toolLabel(tool.toolName, tool.state)}</span>
          </div>
        );
      })}
    </div>
  );
}

const TOOL_LABELS: Record<string, [string, string]> = {
  replaceSelection: ["Replacing selection...", "Replaced selection"],
  insertAtCursor: ["Inserting text...", "Inserted text"],
  applyDiff: ["Applying edit...", "Applied edit"],
  updateFrontmatter: ["Updating metadata...", "Updated metadata"],
  addAuthor: ["Adding author...", "Added author"],
  removeAuthor: ["Removing author...", "Removed author"],
};

function toolLabel(name: string, state: string): string {
  const pair = TOOL_LABELS[name];
  if (!pair) return name;
  return state === "result" ? pair[1] : pair[0];
}

function AgentStatus({ messages }: { messages: UIMessage[] }) {
  const last = messages[messages.length - 1];
  if (!last) return null;

  if (last.role === "assistant") {
    const parts = last.parts ?? [];
    const runningTools = parts
      .map((p) => normalizeToolPart(p))
      .filter((t): t is NonNullable<typeof t> => t !== null && t.state !== "result")
      .map((t) => t.toolName);

    if (runningTools.length > 0) {
      const label = TOOL_LABELS[runningTools[runningTools.length - 1]];
      const text = label ? label[0] : runningTools[runningTools.length - 1];
      return (
        <div className="chat-panel__thinking">
          <Loader size={13} className="spin" />
          <span className="shimmer-text">{text}</span>
        </div>
      );
    }

    const hasText = parts.some((p) => p.type === "text" && (p as any).text?.trim());
    if (hasText) return null;
  }

  return (
    <div className="chat-panel__thinking">
      <Loader size={13} className="spin" />
      <span className="shimmer-text">Thinking...</span>
    </div>
  );
}
