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

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

import { ChatPage } from "../../../src/web/features/chat/ChatPage";
import { ProjectContext } from "../../../src/web/shared/hooks/use-current-project";
import { installFetchMock, jsonResponse, renderWithProviders } from "../test-utils";

const PROJECT_ID = "proj-1";

const MOCK_PROJECT: Project = {
  createdAt: "2026-01-01T00:00:00.000Z",
  description: "",
  id: PROJECT_ID,
  name: "测试项目",
  status: "active",
  updatedAt: "2026-01-01T00:00:00.000Z",
};

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

const CONVERSATION = {
  createdAt: "2026-06-03T00:00:00.000Z",
  id: "conv-1",
  modelId: "model-1",
  projectId: PROJECT_ID,
  title: "测试对话",
  updatedAt: "2026-06-03T00:00:00.000Z",
};

function renderChatPage() {
  return renderWithProviders(
    createElement(ProjectContext.Provider, {
      children: createElement(ChatPage),
      value: MOCK_PROJECT,
    }),
  );
}

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

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

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

describe("ChatPage", () => {
  test("渲染对话侧边栏和欢迎页", async () => {
    setupFetchMock();
    renderChatPage();

    await waitFor(() => {
      expect(screen.getByText("测试对话")).not.toBeNull();
    });

    expect(screen.getByText("你好，我是阿福")).not.toBeNull();
  });

  test("点击新对话按钮创建并选中对话", async () => {
    const calls = setupFetchMock();
    renderChatPage();

    await waitFor(() => {
      expect(screen.getByText("新对话")).not.toBeNull();
    });

    fireEvent.click(screen.getByText("新对话"));

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

  test("点击对话切换选中", async () => {
    setupFetchMock();
    renderChatPage();

    await waitFor(() => {
      expect(screen.getByText("测试对话")).not.toBeNull();
    });

    fireEvent.click(screen.getByText("测试对话"));

    await waitFor(() => {
      expect(screen.queryByText("你好，我是阿福")).toBeNull();
    });
  });

  test("删除对话后列表更新", async () => {
    let deleted = false;
    installFetchMock((call) => {
      if (call.method === "DELETE" && call.url.includes("/conversations/conv-1")) {
        deleted = true;
        return new Response(null, { status: 204 });
      }
      if (call.url.includes("/models")) {
        return jsonResponse({ items: [TEXT_MODEL], total: 1 });
      }
      if (call.url.includes("/conversations") && call.method === "GET") {
        if (deleted) {
          return jsonResponse({ items: [], page: 1, pageSize: 200, total: 0 });
        }
        return jsonResponse({ items: [CONVERSATION], page: 1, pageSize: 200, total: 1 });
      }
      if (call.url.includes("/messages")) {
        return jsonResponse({ items: [], total: 0 });
      }
      return jsonResponse({ error: "not found" }, { status: 404 });
    });

    renderChatPage();

    await waitFor(() => {
      expect(screen.getByText("测试对话")).not.toBeNull();
    });

    fireEvent.click(screen.getByLabelText("删除"));

    await waitFor(() => {
      expect(screen.getByText("确认删除该对话？")).not.toBeNull();
    });

    fireEvent.click(screen.getByText("删 除"));

    await waitFor(() => {
      expect(screen.getByText("暂无对话")).not.toBeNull();
    });
  });
});
