"use client";

import React from "react";
import { useState, useRef, useEffect, useCallback, memo, useMemo } from "react";
import { useRouter } from "next/navigation";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import type { App, Conversation, Message, ToolCall } from "@/lib/types";
import api, { streamChat } from "@/lib/api";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import {
  ArrowLeft,
  Plus,
  Send,
  Loader2,
  MessageSquare,
  Bot,
  Wrench,
  CheckCircle2,
  Sparkles,
  Trash2,
  CheckSquare,
  Square,
  X,
  Copy,
  Download,
  Pencil,
  PanelLeftOpen,
} from "lucide-react";
import { getCategoryIcon, getCategoryColor } from "@/lib/category-config";
import GovMarkdown from "@/components/ui/gov-markdown";
import { toast } from "sonner";

function parseToolCalls(content: string): { cleanContent: string; tools: ToolCall[] } {
  const tools: ToolCall[] = [];
  let cleanContent = content;
  const toolCallRegex = /\[工具调用:\s*(.+?)\]/g;
  const toolResultRegex = /\[工具结果:\s*(.+?)\]/g;
  let match;
  while ((match = toolCallRegex.exec(content)) !== null) {
    const name = match[1].trim();
    if (!tools.find((t) => t.name === name)) tools.push({ name, status: "running" });
  }
  while ((match = toolResultRegex.exec(content)) !== null) {
    const name = match[1].trim();
    const tool = tools.find((t) => t.name === name);
    if (tool) tool.status = "done";
  }
  cleanContent = cleanContent
    .replace(/\[工具调用:\s*.+?\]/g, "")
    .replace(/\[工具结果:\s*.+?\]/g, "")
    .trim();
  return { cleanContent, tools };
}

const AgentMessage = memo(function AgentMessage({
  msg,
  onCopy,
}: {
  msg: Message;
  onCopy: (text: string) => void;
}) {
  if (msg.role === "user") {
    return (
      <div className="flex justify-end group/msg">
        <div className="max-w-[80%]">
          <div className="rounded-2xl px-4 py-2.5 bg-primary text-primary-foreground rounded-br-md shadow-sm">
            <p className="text-sm whitespace-pre-wrap">{msg.content}</p>
          </div>
          <div className="flex justify-end mt-1 opacity-0 group-hover/msg:opacity-100 transition-opacity">
            <button
              onClick={() => onCopy(msg.content)}
              className="flex items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground px-1.5 py-0.5 rounded"
            >
              <Copy className="h-3 w-3" /> 复制
            </button>
          </div>
        </div>
      </div>
    );
  }
  const { cleanContent, tools: parsedTools } = parseToolCalls(msg.content);
  return (
    <div className="flex justify-start group/msg">
      <div className="max-w-[85%] space-y-2">
        {parsedTools.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {parsedTools.map((tool) => (
              <div
                key={tool.name}
                className={`flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs ${
                  tool.status === "done"
                    ? "bg-emerald-50 text-emerald-700"
                    : "bg-amber-50 text-amber-700"
                }`}
              >
                {tool.status === "done" ? (
                  <CheckCircle2 className="h-3 w-3" />
                ) : (
                  <Loader2 className="h-3 w-3 animate-spin" />
                )}
                {tool.name}
              </div>
            ))}
          </div>
        )}
        <div className="rounded-2xl px-5 py-3 bg-white dark:bg-card border border-border/50 rounded-bl-md shadow-sm">
          <GovMarkdown content={cleanContent} />
        </div>
        {cleanContent && (
          <div className="flex mt-1 opacity-0 group-hover/msg:opacity-100 transition-opacity">
            <button
              onClick={() => onCopy(cleanContent)}
              className="flex items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground px-1.5 py-0.5 rounded"
            >
              <Copy className="h-3 w-3" /> 复制
            </button>
          </div>
        )}
      </div>
    </div>
  );
});

interface AgentUIProps {
  app: App;
}

export default function AgentUI({ app }: AgentUIProps) {
  const router = useRouter();
  const queryClient = useQueryClient();
  const [conversationId, setConversationId] = useState<string | undefined>();
  const [messages, setMessages] = useState<Message[]>(
    app.welcome_message && !conversationId
      ? [{ id: "welcome", role: "assistant", content: app.welcome_message }]
      : [],
  );
  const [input, setInput] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);
  const [selectMode, setSelectMode] = useState(false);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [deleteTarget, setDeleteTarget] = useState<{
    type: "single" | "batch";
    id?: string;
    name?: string;
  } | null>(null);
  const [editingConvId, setEditingConvId] = useState<string | null>(null);
  const [editingName, setEditingName] = useState("");
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const abortRef = useRef<AbortController | null>(null);
  const renameInputRef = useRef<HTMLInputElement>(null);

  const appConfig = useMemo(() => {
    try {
      if (typeof app.app_config === "string") return JSON.parse(app.app_config);
      return app.app_config || {};
    } catch {
      return {};
    }
  }, [app.app_config]);

  const tools: string[] = appConfig.tools || [];

  const { data: conversations = [] } = useQuery({
    queryKey: ["conversations", app.id],
    queryFn: async () => {
      const data = await api.get<{ data: Conversation[] }>(`/api/v1/apps/${app.id}/conversations`);
      return data.data || [];
    },
    staleTime: 10_000,
  });

  const scrollToBottom = useCallback(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, []);

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

  useEffect(() => {
    return () => {
      abortRef.current?.abort();
    };
  }, []);

  const loadConversation = useCallback(
    async (convId: string) => {
      setConversationId(convId);
      try {
        const data = await api.get<{ data: Message[] }>(
          `/api/v1/apps/${app.id}/conversations/${convId}/messages`,
        );
        setMessages(data.data || []);
      } catch {
        setMessages([]);
      }
    },
    [app.id],
  );

  const CategoryIconComponent = getCategoryIcon(app.category_slug);
  const categoryColor = getCategoryColor(app.category_slug);

  const suggestedPrompts = useMemo(() => {
    try {
      if (typeof app.suggested_prompts === "string")
        return JSON.parse(app.suggested_prompts) as string[];
      return (app.suggested_prompts as string[]) || [];
    } catch {
      return [];
    }
  }, [app.suggested_prompts]);

  const copyText = useCallback((text: string) => {
    navigator.clipboard.writeText(text);
    toast.success("已复制到剪贴板");
  }, []);

  const exportConversation = useCallback(() => {
    if (messages.length === 0) return;
    const lines = messages
      .filter((m) => m.id !== "welcome")
      .map((m) => {
        const role = m.role === "user" ? "【用户】" : "【AI助手】";
        return `${role}\n${m.content}`;
      });
    const text = `${app.name} - 对话记录\n导出时间：${new Date().toLocaleString("zh-CN")}\n${"=".repeat(40)}\n\n${lines.join("\n\n" + "-".repeat(40) + "\n\n")}`;
    const filename = `${app.name}-对话记录-${new Date().toISOString().slice(0, 10)}.txt`;
    const blob = new Blob([text], { type: "application/octet-stream" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    a.style.display = "none";
    document.body.appendChild(a);
    a.click();
    setTimeout(() => {
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }, 30000);
    toast.success("对话已导出");
  }, [messages, app.name]);

  const sendMessage = useCallback(async () => {
    const text = input.trim();
    if (!text || isStreaming) return;
    const userMsg: Message = { id: `u-${Date.now()}`, role: "user", content: text };
    const assistantMsg: Message = { id: `a-${Date.now()}`, role: "assistant", content: "" };

    setMessages((prev) => [...prev, userMsg, assistantMsg]);
    setInput("");
    setIsStreaming(true);

    const controller = new AbortController();
    abortRef.current = controller;

    try {
      const res = await streamChat(app.id, text, conversationId, controller.signal);
      if (!res.ok) throw new Error("请求失败");
      const reader = res.body?.getReader();
      const decoder = new TextDecoder();
      if (!reader) throw new Error("无法获取响应流");

      let buffer = "";
      let accumulated = "";
      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 raw = line.slice(6);
          if (raw === "[DONE]") break;
          try {
            const event = JSON.parse(raw);
            if (event.conversation_id) setConversationId(event.conversation_id);
            if (event.answer) {
              accumulated += event.answer;
              const snap = accumulated;
              setMessages((prev) =>
                prev.map((m, i) =>
                  i === prev.length - 1 && m.role === "assistant" ? { ...m, content: snap } : m,
                ),
              );
            }
          } catch {
            /* skip */
          }
        }
      }
      queryClient.invalidateQueries({ queryKey: ["conversations", app.id] });
    } catch (err) {
      if ((err as Error).name === "AbortError") return;
      setMessages((prev) =>
        prev.map((m, i) =>
          i === prev.length - 1 && m.role === "assistant" && !m.content
            ? { ...m, content: "抱歉，系统处理异常，请稍后重试。" }
            : m,
        ),
      );
    } finally {
      abortRef.current = null;
      setIsStreaming(false);
    }
  }, [input, isStreaming, app.id, conversationId, queryClient]);

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        sendMessage();
      }
    },
    [sendMessage],
  );

  const startNewConversation = useCallback(() => {
    abortRef.current?.abort();
    setMessages([]);
    setConversationId(undefined);
    setIsStreaming(false);
  }, []);

  const toggleSelect = useCallback((id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  const selectAll = useCallback(() => {
    setSelectedIds(new Set(conversations.map((c) => c.id)));
  }, [conversations]);

  const confirmDeleteSingle = useCallback(
    async (convId: string) => {
      try {
        await api.delete(`/api/v1/apps/${app.id}/conversations/${convId}`);
        if (conversationId === convId) startNewConversation();
        queryClient.invalidateQueries({ queryKey: ["conversations", app.id] });
        toast.success("对话已删除");
      } catch {
        toast.error("删除失败");
      }
      setDeleteTarget(null);
    },
    [app.id, conversationId, startNewConversation, queryClient],
  );

  const confirmBatchDelete = useCallback(async () => {
    if (selectedIds.size === 0) return;
    try {
      await api.post(`/api/v1/apps/${app.id}/conversations/batch-delete`, {
        conversation_ids: Array.from(selectedIds),
      });
      if (conversationId && selectedIds.has(conversationId)) startNewConversation();
      setSelectedIds(new Set());
      setSelectMode(false);
      queryClient.invalidateQueries({ queryKey: ["conversations", app.id] });
      toast.success(`已删除 ${selectedIds.size} 个对话`);
    } catch {
      toast.error("批量删除失败");
    }
    setDeleteTarget(null);
  }, [selectedIds, app.id, conversationId, startNewConversation, queryClient]);

  const startRename = useCallback((convId: string, currentName: string) => {
    setEditingConvId(convId);
    setEditingName(currentName);
    setTimeout(() => renameInputRef.current?.focus(), 50);
  }, []);

  const saveRename = useCallback(async () => {
    if (!editingConvId || !editingName.trim()) {
      setEditingConvId(null);
      return;
    }
    try {
      await api.put(`/api/v1/apps/${app.id}/conversations/${editingConvId}/name`, {
        name: editingName.trim(),
      });
      queryClient.invalidateQueries({ queryKey: ["conversations", app.id] });
      toast.success("已重命名");
    } catch {
      toast.error("重命名失败");
    }
    setEditingConvId(null);
  }, [editingConvId, editingName, app.id, queryClient]);

  return (
    <div className="flex h-[calc(100vh-3.5rem)] overflow-hidden">
      {/* 删除确认弹窗 */}
      <AlertDialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>确认删除</AlertDialogTitle>
            <AlertDialogDescription>
              {deleteTarget?.type === "single"
                ? `确定要删除对话"${deleteTarget.name || "新对话"}"吗？删除后无法恢复。`
                : `确定要删除选中的 ${selectedIds.size} 个对话吗？删除后无法恢复。`}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>取消</AlertDialogCancel>
            <AlertDialogAction
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
              onClick={() => {
                if (deleteTarget?.type === "single" && deleteTarget.id) {
                  confirmDeleteSingle(deleteTarget.id);
                } else {
                  confirmBatchDelete();
                }
              }}
            >
              确认删除
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 手机端侧边栏遮罩层 */}
      {sidebarOpen && (
        <div
          className="fixed inset-0 z-40 bg-black/40 md:hidden"
          onClick={() => setSidebarOpen(false)}
        />
      )}

      {/* 侧边栏 */}
      <div
        className={`fixed inset-y-[3.5rem] left-0 z-50 w-64 border-r bg-background flex flex-col shrink-0 overflow-hidden transition-transform duration-200 md:static md:inset-y-0 md:translate-x-0 ${sidebarOpen ? "translate-x-0" : "-translate-x-full"}`}
      >
        <div className="p-3 border-b space-y-2 shrink-0">
          <Button
            variant="ghost"
            size="sm"
            className="w-full justify-start gap-1.5 text-muted-foreground"
            onClick={() => router.push("/store")}
          >
            <ArrowLeft className="h-3.5 w-3.5" /> 返回应用中心
          </Button>
          <Button
            onClick={startNewConversation}
            className="w-full gap-1.5 bg-blue-900 hover:bg-blue-800 text-white"
            size="sm"
          >
            <Plus className="h-3.5 w-3.5" /> 新对话
          </Button>
        </div>

        {tools.length > 0 && (
          <div className="p-3 border-b shrink-0">
            <p className="text-xs font-medium text-muted-foreground mb-2 flex items-center gap-1">
              <Wrench className="h-3 w-3" /> 可用工具
            </p>
            <div className="flex flex-wrap gap-1.5">
              {tools.map((tool) => (
                <Badge key={tool} variant="outline" className="text-xs font-normal gap-1">
                  <Sparkles className="h-2.5 w-2.5" />
                  {tool}
                </Badge>
              ))}
            </div>
          </div>
        )}

        {conversations.length > 0 && (
          <div className="px-3 py-2 border-b flex items-center justify-between shrink-0">
            <span className="text-xs text-muted-foreground">
              {selectMode ? `已选 ${selectedIds.size} 个` : `${conversations.length} 个对话`}
            </span>
            <div className="flex items-center gap-1">
              {selectMode ? (
                <>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-1.5 text-xs"
                    onClick={selectAll}
                  >
                    全选
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-1.5 text-xs text-destructive hover:text-destructive"
                    onClick={() => setDeleteTarget({ type: "batch" })}
                    disabled={selectedIds.size === 0}
                  >
                    <Trash2 className="h-3 w-3 mr-0.5" /> 删除
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-1.5 text-xs"
                    onClick={() => {
                      setSelectMode(false);
                      setSelectedIds(new Set());
                    }}
                  >
                    <X className="h-3 w-3" />
                  </Button>
                </>
              ) : (
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-6 px-1.5 text-xs"
                  onClick={() => setSelectMode(true)}
                >
                  <CheckSquare className="h-3 w-3 mr-0.5" /> 管理
                </Button>
              )}
            </div>
          </div>
        )}

        <div className="flex-1 overflow-y-auto min-h-0 p-2">
          {conversations.length === 0 ? (
            <p className="text-xs text-muted-foreground text-center py-4">暂无对话历史</p>
          ) : (
            <div className="space-y-0.5">
              {conversations.map((conv) => (
                <div key={conv.id} className="group flex items-center gap-1">
                  {selectMode && (
                    <button onClick={() => toggleSelect(conv.id)} className="shrink-0 p-0.5">
                      {selectedIds.has(conv.id) ? (
                        <CheckSquare className="h-3.5 w-3.5 text-primary" />
                      ) : (
                        <Square className="h-3.5 w-3.5 text-muted-foreground" />
                      )}
                    </button>
                  )}
                  {editingConvId === conv.id ? (
                    <input
                      ref={renameInputRef}
                      value={editingName}
                      onChange={(e) => setEditingName(e.target.value)}
                      onBlur={saveRename}
                      onKeyDown={(e) => {
                        if (e.key === "Enter") saveRename();
                        if (e.key === "Escape") setEditingConvId(null);
                      }}
                      className="flex-1 px-2 py-1 text-sm border rounded-md bg-background focus:outline-none focus:ring-1 focus:ring-primary"
                      maxLength={50}
                    />
                  ) : (
                    <button
                      onClick={() => !selectMode && loadConversation(conv.id)}
                      onDoubleClick={() => !selectMode && startRename(conv.id, conv.name)}
                      className={`flex-1 text-left p-2 rounded-md text-sm truncate transition-colors ${
                        conversationId === conv.id ? "bg-muted font-medium" : "hover:bg-muted/60"
                      }`}
                      title={`${conv.name}\n双击重命名`}
                    >
                      <MessageSquare className="h-3.5 w-3.5 inline mr-1.5 opacity-50" />
                      {conv.name || "新对话"}
                    </button>
                  )}
                  {!selectMode && editingConvId !== conv.id && (
                    <div className="shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity">
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          startRename(conv.id, conv.name);
                        }}
                        className="p-1 rounded hover:bg-muted"
                        title="重命名"
                      >
                        <Pencil className="h-3 w-3" />
                      </button>
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          setDeleteTarget({ type: "single", id: conv.id, name: conv.name });
                        }}
                        className="p-1 rounded hover:bg-destructive/10 hover:text-destructive"
                        title="删除对话"
                      >
                        <Trash2 className="h-3 w-3" />
                      </button>
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      {/* 主对话区域 */}
      <div className="flex-1 flex flex-col min-w-0 overflow-hidden">
        <div className="border-b px-3 md:px-5 py-3 flex items-center gap-2 md:gap-3 shrink-0">
          <button
            className="md:hidden p-1.5 rounded-md text-muted-foreground hover:bg-muted"
            onClick={() => setSidebarOpen(true)}
          >
            <PanelLeftOpen className="h-4 w-4" />
          </button>
          <div
            className={`flex h-9 w-9 items-center justify-center rounded-xl ${categoryColor} shrink-0`}
          >
            {CategoryIconComponent
              ? React.createElement(CategoryIconComponent, { className: "h-4.5 w-4.5" })
              : null}
          </div>
          <div className="min-w-0">
            <h1 className="font-semibold text-sm truncate">{app.name}</h1>
            <p className="text-xs text-muted-foreground truncate max-w-[150px] md:max-w-none">
              {app.description}
            </p>
          </div>
          <div className="ml-auto flex items-center gap-1 md:gap-2">
            {messages.length > 1 && (
              <Button
                variant="ghost"
                size="sm"
                className="h-7 gap-1.5 text-xs"
                onClick={exportConversation}
              >
                <Download className="h-3 w-3" /> 导出
              </Button>
            )}
            <div className="flex items-center gap-1.5 text-xs text-blue-800 bg-blue-100 px-2 py-1 rounded-full font-medium">
              <Bot className="h-3 w-3" /> 智能体
            </div>
          </div>
        </div>

        <div className="flex-1 overflow-y-auto min-h-0 p-4">
          <div className="max-w-3xl mx-auto space-y-4">
            {messages.map((msg) => (
              <AgentMessage key={msg.id} msg={msg} onCopy={copyText} />
            ))}
            {messages.length <= 1 && suggestedPrompts.length > 0 && (
              <div className="flex flex-wrap gap-2 mt-4">
                {suggestedPrompts.map((prompt: string, i: number) => (
                  <Button
                    key={i}
                    variant="outline"
                    size="sm"
                    className="text-xs"
                    onClick={() => {
                      setInput(prompt);
                      textareaRef.current?.focus();
                    }}
                  >
                    {prompt}
                  </Button>
                ))}
              </div>
            )}
            <div ref={messagesEndRef} />
          </div>
        </div>

        <div className="border-t p-2 md:p-4 shrink-0">
          <div className="max-w-3xl mx-auto flex gap-2">
            <Textarea
              ref={textareaRef}
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyDown={handleKeyDown}
              placeholder="输入消息... (Enter 发送，Shift+Enter 换行)"
              className="resize-none min-h-[44px] max-h-32"
              rows={1}
              disabled={isStreaming}
            />
            <Button
              onClick={sendMessage}
              disabled={!input.trim() || isStreaming}
              className="shrink-0 gap-1.5"
            >
              {isStreaming ? (
                <Loader2 className="h-4 w-4 animate-spin" />
              ) : (
                <Send className="h-4 w-4" />
              )}
              {isStreaming ? "思考中" : "发送"}
            </Button>
          </div>
        </div>
      </div>
    </div>
  );
}
