import {
  fireEvent,
  render,
  screen,
  waitFor,
  within,
} from "@testing-library/react";
import { afterEach, beforeEach, expect, test, vi } from "vitest";

import { SubmitWorkbench } from "@/features/orders/submit-workbench";
import {
  GARMENT_LIBRARY_FIXTURES,
  MODEL_LIBRARY_FIXTURES,
  SCENE_LIBRARY_FIXTURES,
} from "@/lib/mock/libraries";

const { pushMock } = vi.hoisted(() => ({
  pushMock: vi.fn(),
}));

vi.mock("next/navigation", () => ({
  useRouter: () => ({
    push: pushMock,
  }),
}));

type LibraryType = "models" | "scenes" | "garments";

function createLibraryPayload(libraryType: LibraryType) {
  const fixtureMap = {
    models: MODEL_LIBRARY_FIXTURES,
    scenes: SCENE_LIBRARY_FIXTURES,
    garments: GARMENT_LIBRARY_FIXTURES,
  };

  return {
    mode: "placeholder",
    message: "资源库当前使用占位数据，真实后端接口尚未提供。",
    data: {
      items: fixtureMap[libraryType],
    },
  };
}

function createFetchMock({
  orderResponse,
}: {
  orderResponse?: Response;
} = {}) {
  return vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
    const url = typeof input === "string" ? input : input.toString();

    if (url === "/api/libraries/models") {
      return new Response(JSON.stringify(createLibraryPayload("models")), {
        status: 200,
        headers: { "content-type": "application/json" },
      });
    }

    if (url === "/api/libraries/scenes") {
      return new Response(JSON.stringify(createLibraryPayload("scenes")), {
        status: 200,
        headers: { "content-type": "application/json" },
      });
    }

    if (url === "/api/libraries/garments") {
      return new Response(JSON.stringify(createLibraryPayload("garments")), {
        status: 200,
        headers: { "content-type": "application/json" },
      });
    }

    if (url === "/api/orders" && init?.method === "POST" && orderResponse) {
      return orderResponse;
    }

    throw new Error(`Unhandled fetch: ${url}`);
  });
}

async function chooseSelectOption(label: string, optionName: string) {
  fireEvent.click(screen.getByRole("combobox", { name: label }));
  fireEvent.click(await screen.findByRole("option", { name: optionName }));
}

async function chooseLibraryResource(label: string, resourceName: string) {
  fireEvent.click(screen.getByRole("button", { name: `选择${label}` }));

  const dialog = await screen.findByRole("dialog", { name: `选择${label}` });
  fireEvent.click(within(dialog).getByRole("button", { name: resourceName }));

  await waitFor(() => {
    expect(
      screen.queryByRole("dialog", { name: `选择${label}` }),
    ).not.toBeInTheDocument();
  });
}

beforeEach(() => {
  pushMock.mockReset();
});

afterEach(() => {
  vi.unstubAllGlobals();
});

test("forces low customers to use auto_basic and mid customers to use semi_pro", async () => {
  vi.stubGlobal("fetch", createFetchMock());

  render(<SubmitWorkbench />);

  await screen.findByRole("button", { name: "选择模特资源" });

  await chooseSelectOption("客户层级", "低客单 low");

  expect(screen.getByRole("combobox", { name: "服务模式" })).toHaveTextContent(
    "自动基础处理 auto_basic",
  );
  fireEvent.click(screen.getByRole("combobox", { name: "服务模式" }));
  expect(
    screen.getByRole("option", { name: "半人工专业处理 semi_pro" }),
  ).toHaveAttribute("data-disabled");
  fireEvent.keyDown(document.activeElement ?? document.body, {
    key: "Escape",
  });

  await chooseSelectOption("客户层级", "中客单 mid");

  expect(screen.getByRole("combobox", { name: "服务模式" })).toHaveTextContent(
    "半人工专业处理 semi_pro",
  );
  fireEvent.click(screen.getByRole("combobox", { name: "服务模式" }));
  expect(
    screen.getByRole("option", { name: "自动基础处理 auto_basic" }),
  ).toHaveAttribute("data-disabled");
});

test("preserves selected values when order submission fails", async () => {
  vi.stubGlobal(
    "fetch",
    createFetchMock({
      orderResponse: new Response(
        JSON.stringify({
          error: "BACKEND_UNAVAILABLE",
          message: "后端暂时不可用，请稍后重试。",
        }),
        {
          status: 502,
          headers: { "content-type": "application/json" },
        },
      ),
    }),
  );

  render(<SubmitWorkbench />);

  await screen.findByRole("button", { name: "选择模特资源" });

  await chooseSelectOption("客户层级", "低客单 low");
  await chooseLibraryResource("模特资源", "Ava / Studio");
  await chooseLibraryResource("场景资源", "Loft Window");
  await chooseLibraryResource("服装资源", "Structured Coat 01");

  const summaryCard = screen.getByRole("region", { name: "提单摘要" });
  expect(within(summaryCard).getByText("Ava / Studio")).toBeInTheDocument();
  expect(within(summaryCard).getByText("Loft Window")).toBeInTheDocument();
  expect(within(summaryCard).getByText("Structured Coat 01")).toBeInTheDocument();

  fireEvent.click(screen.getByRole("button", { name: "提交订单" }));

  expect(
    await screen.findByText("后端暂时不可用，请稍后重试。"),
  ).toBeInTheDocument();
  expect(screen.getByRole("combobox", { name: "客户层级" })).toHaveTextContent(
    "低客单 low",
  );
  expect(screen.getByRole("combobox", { name: "服务模式" })).toHaveTextContent(
    "自动基础处理 auto_basic",
  );
  expect(screen.getAllByText("Ava / Studio").length).toBeGreaterThan(1);
  expect(screen.getAllByText("Loft Window").length).toBeGreaterThan(1);
  expect(screen.getAllByText("Structured Coat 01").length).toBeGreaterThan(1);
});

test("submits the selected resources, surfaces returned ids, and redirects to the order detail page", async () => {
  const fetchMock = createFetchMock({
    orderResponse: new Response(
      JSON.stringify({
        mode: "proxy",
        data: {
          orderId: 77,
          workflowId: "wf-77",
          status: "created",
        },
      }),
      {
        status: 201,
        headers: { "content-type": "application/json" },
      },
    ),
  });

  vi.stubGlobal("fetch", fetchMock);

  render(<SubmitWorkbench />);

  await screen.findByRole("button", { name: "选择模特资源" });

  await chooseSelectOption("客户层级", "低客单 low");
  await chooseLibraryResource("模特资源", "Ava / Studio");
  await chooseLibraryResource("场景资源", "Loft Window");
  await chooseLibraryResource("服装资源", "Structured Coat 01");

  fireEvent.click(screen.getByRole("button", { name: "提交订单" }));

  await waitFor(() => {
    expect(fetchMock).toHaveBeenCalledWith(
      "/api/orders",
      expect.objectContaining({
        method: "POST",
        body: JSON.stringify({
          customer_level: "low",
          service_mode: "auto_basic",
          model_id: 101,
          garment_asset_id: 303,
          scene_ref_asset_id: 404,
        }),
      }),
    );
  });

  expect(
    await screen.findByText("订单 #77 已创建，正在跳转到详情页。"),
  ).toBeInTheDocument();
  expect(screen.getByText("工作流 ID wf-77")).toBeInTheDocument();

  await waitFor(() => {
    expect(pushMock).toHaveBeenCalledWith("/orders/77");
  });
});

test("allows submitting without selecting a scene resource", async () => {
  const fetchMock = createFetchMock({
    orderResponse: new Response(
      JSON.stringify({
        mode: "proxy",
        data: {
          orderId: 88,
          workflowId: "wf-88",
          status: "created",
        },
      }),
      {
        status: 201,
        headers: { "content-type": "application/json" },
      },
    ),
  });

  vi.stubGlobal("fetch", fetchMock);

  render(<SubmitWorkbench />);

  await screen.findByRole("button", { name: "选择模特资源" });

  await chooseSelectOption("客户层级", "低客单 low");
  await chooseLibraryResource("模特资源", "Ava / Studio");
  await chooseLibraryResource("服装资源", "Structured Coat 01");

  fireEvent.click(screen.getByRole("button", { name: "提交订单" }));

  await waitFor(() => {
    expect(fetchMock).toHaveBeenCalledWith(
      "/api/orders",
      expect.objectContaining({
        method: "POST",
        body: JSON.stringify({
          customer_level: "low",
          service_mode: "auto_basic",
          model_id: 101,
          garment_asset_id: 303,
        }),
      }),
    );
  });
});

test("opens a shared resource manager modal and picks a resource card for each library type", async () => {
  vi.stubGlobal("fetch", createFetchMock());

  render(<SubmitWorkbench />);

  await screen.findByRole("button", { name: "选择模特资源" });

  fireEvent.click(screen.getByRole("button", { name: "选择模特资源" }));

  const modelDialog = await screen.findByRole("dialog", { name: "选择模特资源" });
  expect(within(modelDialog).getByTestId("resource-picker-masonry").className).toContain(
    "columns-1",
  );
  expect(
    within(modelDialog).getByRole("button", { name: "Ava / Studio" }),
  ).toBeInTheDocument();

  fireEvent.click(within(modelDialog).getByRole("button", { name: "Ava / Studio" }));

  await waitFor(() => {
    expect(
      screen.queryByRole("dialog", { name: "选择模特资源" }),
    ).not.toBeInTheDocument();
  });

  const summaryCard = screen.getByRole("region", { name: "提单摘要" });
  expect(within(summaryCard).getByText("Ava / Studio")).toBeInTheDocument();
});
