import { expect, test, type APIRequestContext } from "@playwright/test";

const PASSWORD = "SmokePass123!";
const apiBase = process.env.E2E_API_BASE || "/api/v1";
const apiOrigin = apiBase.endsWith("/api/v1")
  ? apiBase.slice(0, -"/api/v1".length)
  : "";

const routeBrowserApiToTestApi = async (
  page: import("@playwright/test").Page,
) => {
  if (!apiOrigin) return;
  await page.route("**/api/v1/**", async (route) => {
    const sourceUrl = new URL(route.request().url());
    const response = await route.fetch({
      url: `${apiOrigin}${sourceUrl.pathname}${sourceUrl.search}`,
    });
    await route.fulfill({ response });
  });
};

/** 登录操作，遇到 429 限流自动等待重试 */
async function loginWithRetry(
  request: APIRequestContext,
  email: string,
  password: string,
  maxRetries = 2,
) {
  for (let i = 0; i <= maxRetries; i++) {
    const response = await request.post(`${apiBase}/auth/login`, {
      data: { email, password },
    });
    if (response.status() !== 429) return response;
    console.log(`[login] 触发限流，等待 65s 后重试 (${i + 1}/${maxRetries})`);
    await new Promise((r) => setTimeout(r, 65000));
  }
  return request.post(`${apiBase}/auth/login`, {
    data: { email, password },
  });
}

type ProjectResponse = { id: string };
type LibraryResponse = { id: string };

test.describe("Core media upload flow", () => {
  test.describe.configure({ timeout: 180_000 });
  test("uploads a video asset and shows it in the asset library", async ({
    page,
    request,
  }) => {
    test.setTimeout(120_000);

    await routeBrowserApiToTestApi(page);
    const suffix = Date.now().toString(36);
    const email = `e2e-mov-${suffix}@example.com`;
    const username = `e2e_mov_${suffix}`;

    const register = await request.post(`${apiBase}/auth/register`, {
      data: {
        email,
        username,
        password: PASSWORD,
        display_name: username,
      },
    });
    expect(register.status(), await register.text()).toBe(201);

    const registerData = (await register.json()) as { user_id: string };

    const login = await loginWithRetry(request, email, PASSWORD);
    expect(login.status(), await login.text()).toBe(200);
    const loginData = (await login.json()) as { access_token: string };
    const headers = { Authorization: `Bearer ${loginData.access_token}` };

    const project = await request.post(`${apiBase}/projects`, {
      headers,
      data: {
        name: `E2E Project ${suffix}`,
        description: "Playwright upload smoke",
      },
    });
    expect(project.status(), await project.text()).toBe(200);
    const projectData = (await project.json()) as ProjectResponse;

    const library = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectData.id,
        name: `E2E Video Library ${suffix}`,
        kind: "video",
      },
    });
    expect(library.status(), await library.text()).toBe(200);
    const libraryData = (await library.json()) as LibraryResponse;

    await page.addInitScript(
      ({ token, user }) => {
        localStorage.setItem("access_token", token);
        localStorage.setItem(
          "auth-storage",
          JSON.stringify({
            state: { user, isAuthenticated: true },
            version: 0,
          }),
        );
      },
      {
        token: loginData.access_token,
        user: {
          id: registerData.user_id,
          user_id: registerData.user_id,
          email,
          username,
          display_name: username,
          is_email_verified: true,
          email_verified: true,
        },
      },
    );

    await page.goto("/app/assets");
    await expect(page.locator(".xx-assets-layout")).toBeVisible({
      timeout: 20_000,
    });

    const upload = await request.post(`${apiBase}/upload`, {
      headers,
      multipart: {
        project_id: projectData.id,
        library_id: libraryData.id,
        file: {
          name: "e2e-sample.MOV",
          mimeType: "video/quicktime",
          buffer: Buffer.from("playwright mov upload smoke"),
        },
      },
    });
    expect(upload.status(), await upload.text()).toBe(200);

    await expect(
      page.getByText(/上传失败|素材列表加载失败|素材库加载失败/),
    ).toHaveCount(0, { timeout: 5_000 });

    await expect
      .poll(
        async () => {
          const assets = await request.get(`${apiBase}/assets`, {
            headers,
            params: { library_id: libraryData.id },
          });
          if (!assets.ok()) {
            return `http_${assets.status()}`;
          }
          const data = (await assets.json()) as {
            items: Array<{
              name: string;
              status: string;
              file_type?: string;
              mime_type?: string;
            }>;
          };
          const asset = data.items.find(
            (item) => item.name === "e2e-sample.MOV",
          );
          return asset
            ? `${asset.mime_type || asset.file_type || ""}:${asset.status}`
            : "missing";
        },
        { timeout: 30_000, intervals: [1_000, 2_000, 3_000] },
      )
      .toMatch(/^(video\/quicktime|video\/mp4|video)?:ready$/);

    // Select the test library from sidebar
    await page
      .locator(".xx-asset-library-item")
      .filter({ hasText: `E2E Video Library ${suffix}` })
      .click({ force: true });

    await page.reload();
    await expect(page.locator(".xx-assets-content")).toBeVisible({
      timeout: 20_000,
    });
    await expect(page.getByText("e2e-sample.MOV", { exact: true })).toBeVisible(
      {
        timeout: 20_000,
      },
    );

    // Verify asset card shows status
    const assetCard = page
      .locator(".xx-asset-card")
      .filter({ hasText: "e2e-sample.MOV" });
    await expect(assetCard).toBeVisible();
    await expect(assetCard.locator(".xx-asset-diagnose-btn")).toBeVisible();

    await expect(page.getByText(/素材加载失败|上传失败/)).toHaveCount(0);
  });
});
