import { fireEvent, screen, waitFor } from "@testing-library/react";
import { describe, expect, mock, test } from "bun:test";
import { createElement } from "react";

import type { Conversation, Model } from "../../../src/shared/api";

import { ChatPanel } from "../../../src/web/consoles/workbench/components/chat/ChatPanel";
import { installFetchMock, jsonResponse, renderWithProviders } from "../test-utils";

const PROJECT_ID = "proj-1";

const TEXT_MODEL: Model = {
  capabilities: ["text"],
  contextLength: null,
  createdAt: "2024-01-01T00:00:00.000Z",
  id: "model-1",
  maxOutputTokens: null,
  modelId: "gpt-4o",
  name: "GPT-4o",
  providerId: "pv1",
  updatedAt: "2024-01-01T00:00:00.000Z",
};

const CONVERSATION: Conversation = {
  createdAt: "2024-01-01T00:00:00.000Z",
  id: "conv-1",
  modelId: "model-1",
  projectId: PROJECT_ID,
  title: "新会话",
  updatedAt: "2024-01-01T00:00:00.000Z",
};

const noop = () => {
  return undefined;
};

void mock.module("@ai-sdk/react", () => ({
  useChat: () => ({
    messages: [],
    regenerate: noop,
    sendMessage: noop,
    setMessages: (msgs: unknown) => msgs,
    status: "ready",
    stop: noop,
  }),
}));

void mock.module("ai", () => ({
  DefaultChatTransport: function () {
    return undefined;
  },
}));

function getSenderTextarea() {
  return screen.getByPlaceholderText("输入消息...");
}

function setupFetchMock() {
  return installFetchMock((call) => {
    if (call.url.includes("/models")) {
      return jsonResponse({ items: [TEXT_MODEL], total: 1 });
    }
    if (call.url.endsWith("/conversations") && call.method === "POST") {
      return jsonResponse({ conversation: { ...CONVERSATION, id: "conv-new" } }, { status: 201 });
    }
    if (/\/conversations\/conv-1$/.exec(call.url)) {
      return jsonResponse({ conversation: CONVERSATION });
    }
    if (call.url.includes("/messages")) {
      return jsonResponse({ items: [], total: 0 });
    }
    if (/\/conversations$/.exec(call.url) && call.method === "GET") {
      return jsonResponse({ items: [], total: 0 });
    }
    return jsonResponse({ error: "not found" }, { status: 404 });
  });
}

describe("ChatPanel", () => {
  describe("欢迎页", () => {
    test("无会话时显示欢迎页和输入框", () => {
      setupFetchMock();
      renderWithProviders(
        createElement(ChatPanel, {
          conversationId: null,
          onConversationCreated: noop,
          projectId: PROJECT_ID,
        }),
      );

      expect(screen.getByText("你好，我是阿福")).toBeTruthy();
      expect(screen.getByText("有什么我可以帮助你的吗？")).toBeTruthy();
      expect(getSenderTextarea()).toBeTruthy();
    });
  });

  describe("自动创建会话", () => {
    test("输入并发送后自动创建会话并通知父组件", async () => {
      const calls = setupFetchMock();
      const onCreated = mock<(id: string) => void>(() => undefined);

      renderWithProviders(
        createElement(ChatPanel, {
          conversationId: null,
          onConversationCreated: onCreated,
          projectId: PROJECT_ID,
        }),
      );

      const textarea = getSenderTextarea();
      fireEvent.change(textarea, { target: { value: "你好" } });
      fireEvent.keyDown(textarea, { key: "Enter" });

      await waitFor(() => {
        expect(onCreated).toHaveBeenCalledWith("conv-new");
      });

      const createCall = calls.find((c) => c.url.endsWith("/conversations") && c.method === "POST");
      expect(createCall).toBeTruthy();
    });

    test("创建会话失败时恢复输入文本", async () => {
      installFetchMock((call) => {
        if (call.url.includes("/models")) {
          return jsonResponse({ items: [TEXT_MODEL], total: 1 });
        }
        if (call.url.endsWith("/conversations") && call.method === "POST") {
          return jsonResponse({ error: "服务器错误" }, { status: 500 });
        }
        return jsonResponse({ error: "not found" }, { status: 404 });
      });

      renderWithProviders(
        createElement(ChatPanel, {
          conversationId: null,
          onConversationCreated: noop,
          projectId: PROJECT_ID,
        }),
      );

      const textarea = getSenderTextarea();
      fireEvent.change(textarea, { target: { value: "测试输入" } });
      fireEvent.keyDown(textarea, { key: "Enter" });

      await waitFor(() => {
        expect((textarea as HTMLTextAreaElement).value).toBe("测试输入");
      });
    });
  });

  describe("聊天面板", () => {
    test("选中会话时显示消息列表区域", () => {
      setupFetchMock();
      renderWithProviders(
        createElement(ChatPanel, {
          conversationId: "conv-1",
          onConversationCreated: noop,
          projectId: PROJECT_ID,
        }),
      );

      expect(screen.queryByText("你好，我是阿福")).toBeNull();
      expect(getSenderTextarea()).toBeTruthy();
    });
  });
});
