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

import type { Provider } from "../../../src/shared/api";

import { App } from "../../../src/web/app";
import { ProviderFormModal } from "../../../src/web/features/models/components/ProviderFormModal";
import { installFetchMock, jsonResponse, mockMetaResponse, renderWithProviders } from "../test-utils";

const ENABLED_PROVIDER: Provider = {
  apiKey: "sk-test",
  baseUrl: "https://api.openai.com/v1",
  createdAt: "2024-01-01T00:00:00.000Z",
  id: "pv1",
  name: "OpenAI",
  type: "openai",
  updatedAt: "2024-01-01T00:00:00.000Z",
};

function clickLatestConfirmButton() {
  const buttons = screen.getAllByRole("button", { name: /OK|确\s*定/ });
  fireEvent.click(buttons[buttons.length - 1]!);
}

describe("ProviderFormModal", () => {
  test("编辑供应商表单只提交变更字段", async () => {
    const updateCalls: unknown[] = [];

    renderWithProviders(
      createElement(ProviderFormModal, {
        editingProvider: ENABLED_PROVIDER,
        onCancel: () => undefined,
        onCreate: () => Promise.resolve(),
        onOpenChange: () => undefined,
        onTest: () => Promise.resolve({ message: "连接成功", ok: true }),
        onUpdate: (args: unknown) => {
          updateCalls.push(args);
          return Promise.resolve();
        },
        open: true,
        submitting: false,
      }),
    );

    await screen.findByPlaceholderText("请输入供应商名称");
    fireEvent.change(screen.getByPlaceholderText("请输入供应商名称"), { target: { value: "New OpenAI" } });
    clickLatestConfirmButton();

    await waitFor(() => expect(updateCalls.length).toBe(1));
    expect(updateCalls[0]).toEqual({ data: { name: "New OpenAI" }, id: "pv1" });
  }, 30000);

  test("新建供应商默认使用 openai-compatible 类型", async () => {
    const createCalls: unknown[] = [];

    renderWithProviders(
      createElement(ProviderFormModal, {
        editingProvider: null,
        onCancel: () => undefined,
        onCreate: (data: unknown) => {
          createCalls.push(data);
          return Promise.resolve();
        },
        onOpenChange: () => undefined,
        onTest: () => Promise.resolve({ message: "连接成功", ok: true }),
        onUpdate: () => Promise.resolve(),
        open: true,
        submitting: false,
      }),
    );

    await screen.findByPlaceholderText("请输入供应商名称");
    fireEvent.change(screen.getByPlaceholderText("请输入供应商名称"), { target: { value: "兼容供应商" } });
    fireEvent.change(screen.getByPlaceholderText("https://api.openai.com/v1"), {
      target: { value: "https://api.test.com/v1" },
    });
    fireEvent.change(screen.getByPlaceholderText("请输入 API Key"), { target: { value: "sk-test" } });
    clickLatestConfirmButton();

    await waitFor(() => expect(createCalls.length).toBe(1));
    expect(createCalls[0]).toEqual({
      apiKey: "sk-test",
      baseUrl: "https://api.test.com/v1",
      name: "兼容供应商",
      type: "openai-compatible",
    });
  }, 30000);

  test("供应商表单可使用当前表单配置测试连接", async () => {
    const testCalls: unknown[] = [];

    renderWithProviders(
      createElement(ProviderFormModal, {
        editingProvider: null,
        onCancel: () => undefined,
        onCreate: () => Promise.resolve(),
        onOpenChange: () => undefined,
        onTest: (data: unknown) => {
          testCalls.push(data);
          return Promise.resolve({ message: "连接成功", ok: true });
        },
        onUpdate: () => Promise.resolve(),
        open: true,
        submitting: false,
      }),
    );

    await screen.findByPlaceholderText("请输入供应商名称");
    fireEvent.change(screen.getByPlaceholderText("请输入供应商名称"), { target: { value: "兼容供应商" } });
    fireEvent.change(screen.getByPlaceholderText("https://api.openai.com/v1"), {
      target: { value: "https://api.test.com/v1" },
    });
    fireEvent.change(screen.getByPlaceholderText("请输入 API Key"), { target: { value: "sk-test" } });
    fireEvent.click(screen.getByRole("button", { name: "测试连接" }));

    await waitFor(() => expect(testCalls.length).toBe(1));
    expect(testCalls[0]).toEqual({
      apiKey: "sk-test",
      baseUrl: "https://api.test.com/v1",
      name: "兼容供应商",
      type: "openai-compatible",
    });
  }, 30000);
});

const TEST_PROVIDER: Provider = {
  apiKey: "sk-test",
  baseUrl: "https://api.openai.com/v1",
  createdAt: "2024-01-01T00:00:00.000Z",
  id: "pv1",
  name: "OpenAI",
  type: "openai",
  updatedAt: "2024-01-01T00:00:00.000Z",
};

function createProviderFetchMock() {
  let providers = [TEST_PROVIDER];

  return installFetchMock((call) => {
    if (call.url.includes("/api/meta")) return mockMetaResponse();

    const url = new URL(call.url, "http://localhost");

    if (url.pathname === "/api/providers" && call.method === "POST") {
      const data = JSON.parse(typeof call.body === "string" ? call.body : "{}") as Record<string, unknown>;
      const created: Provider = {
        ...TEST_PROVIDER,
        ...data,
        createdAt: "2024-01-02T00:00:00.000Z",
        id: "pv-new",
        updatedAt: "2024-01-02T00:00:00.000Z",
      };
      providers = [created, ...providers];
      return jsonResponse({ provider: created }, { status: 201 });
    }

    if (/^\/api\/providers\/[^/]+$/.exec(url.pathname) && call.method === "PATCH") {
      const id = url.pathname.split("/").pop()!;
      const data = JSON.parse(typeof call.body === "string" ? call.body : "{}") as Record<string, unknown>;
      const existing = providers.find((p) => p.id === id) ?? TEST_PROVIDER;
      const updated = { ...existing, ...(data as Partial<Provider>) };
      providers = providers.map((p) => (p.id === id ? updated : p));
      return jsonResponse({ provider: updated });
    }

    if (/^\/api\/providers\/[^/]+$/.exec(url.pathname) && call.method === "DELETE") {
      const id = url.pathname.split("/").pop()!;
      providers = providers.filter((p) => p.id !== id);
      return new Response(null, { status: 204 });
    }

    if (url.pathname === "/api/providers" && call.method === "GET") {
      const keyword = url.searchParams.get("keyword") ?? "";
      const items = keyword ? providers.filter((p) => p.name.includes(keyword)) : providers;
      return jsonResponse({ items, page: 1, pageSize: 20, total: items.length });
    }

    if (/\/api\/providers\/[^/]+\/test$/.exec(url.pathname) && call.method === "POST") {
      return jsonResponse({ message: "连接成功", ok: true });
    }

    return jsonResponse({ error: "Not Found" }, { status: 404 });
  });
}

describe("ProviderListPage", () => {
  test("渲染供应商列表页并请求供应商数据", async () => {
    const calls = createProviderFetchMock();

    renderWithProviders(createElement(App), { initialRoute: "/models/providers" });

    await waitFor(() => {
      expect(screen.getAllByText("OpenAI").length).toBeGreaterThan(0);
    });

    expect(screen.getByPlaceholderText("搜索供应商名称")).not.toBeNull();
    expect(screen.getByRole("button", { name: /新建供应商/ })).not.toBeNull();
    expect(calls.some((call) => call.url.includes("/api/providers"))).toBe(true);
  }, 30000);

  test("搜索供应商更新请求参数", async () => {
    const calls = createProviderFetchMock();

    renderWithProviders(createElement(App), { initialRoute: "/models/providers" });
    await waitFor(() => expect(screen.getAllByText("OpenAI").length).toBeGreaterThan(0));

    const input = screen.getByPlaceholderText("搜索供应商名称");
    fireEvent.change(input, { target: { value: "Open" } });
    fireEvent.keyDown(input, { key: "Enter" });
    await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=Open"))).toBe(true));
  }, 30000);

  test("新建供应商弹窗可以打开", async () => {
    createProviderFetchMock();

    renderWithProviders(createElement(App), { initialRoute: "/models/providers" });
    await screen.findByRole("button", { name: /新建供应商/ });

    fireEvent.click(screen.getByRole("button", { name: /新建供应商/ }));
    await screen.findByPlaceholderText("请输入供应商名称");
  }, 30000);
});
