/**
 * 素材库流程 E2E 测试
 *
 * 覆盖：创建素材库、列出素材库、创建素材记录
 * 每个测试独立，先注册登录获取 auth token。
 */
import { expect, test, type APIRequestContext } from "@playwright/test";

const PASSWORD = "Test123456!";
const apiBase = process.env.E2E_API_BASE || "/api/v1";

function uniqueEmail(prefix: string): string {
  return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}@example.com`;
}

function uniqueUsername(prefix: string): string {
  return `${prefix}_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
}

/** 登录操作，遇到 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 },
  });
}

/** 注册并登录，返回 { headers, email, username, userId } */
async function createAuthedUser(request: APIRequestContext, label: string) {
  const email = uniqueEmail(label);
  const username = uniqueUsername(label);

  const reg = await request.post(`${apiBase}/auth/register`, {
    data: { email, password: PASSWORD, username, display_name: `E2E ${label}` },
  });
  expect(reg.ok(), `注册应成功: ${await reg.text()}`).toBeTruthy();
  const regData = await reg.json();

  const login = await loginWithRetry(request, email, PASSWORD);
  expect(login.ok(), `登录应成功: ${await login.text()}`).toBeTruthy();
  const loginData = await login.json();

  return {
    headers: { Authorization: `Bearer ${loginData.access_token}` },
    email,
    username,
    userId: regData.user_id,
  };
}

/** 创建一个项目并返回 project id */
async function createProject(
  request: APIRequestContext,
  headers: Record<string, string>,
  suffix: string,
): Promise<string> {
  const resp = await request.post(`${apiBase}/projects`, {
    headers,
    data: { name: `Asset Test Proj ${suffix}`, description: "E2E asset test" },
  });
  expect(resp.ok(), `创建项目应成功: ${await resp.text()}`).toBeTruthy();
  const data = await resp.json();
  return data.id;
}

test.describe("素材库流程", () => {
  // 登录限流 10次/60s，测试可能触发限流等待，给足够超时
  test.describe.configure({ timeout: 180_000 });

  test("创建素材库", async ({ request }) => {
    const { headers } = await createAuthedUser(request, "lib-create");
    const projectId = await createProject(
      request,
      headers,
      Date.now().toString(),
    );

    const response = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: `视频素材库 ${Date.now()}`,
        kind: "video",
      },
    });

    expect(
      response.ok(),
      `创建素材库应返回 2xx，实际: ${response.status()} ${await response.text()}`,
    ).toBeTruthy();

    const data = await response.json();
    expect(data.id, "应返回素材库 ID").toBeTruthy();
    expect(data.name).toContain("视频素材库");
    expect(data.kind).toBe("video");
    expect(data.project_id).toBe(projectId);
  });

  test("创建素材库 - 无效 kind 反向", async ({ request }) => {
    const { headers } = await createAuthedUser(request, "lib-badkind");
    const projectId = await createProject(
      request,
      headers,
      Date.now().toString(),
    );

    const response = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: "Bad Kind Library",
        kind: "invalid_kind",
      },
    });

    // kind 有 pattern 校验 ^（video|voice|image)$，应返回 422
    expect([400, 422]).toContain(response.status());
  });

  test("创建素材库 - 不存在的项目反向", async ({ request }) => {
    const { headers } = await createAuthedUser(request, "lib-nopj");

    const response = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: "nonexistent-project-999",
        name: "Orphan Library",
        kind: "video",
      },
    });

    expect(response.status(), "不存在的项目应返回 404").toBe(404);
  });

  test("列出素材库", async ({ request }) => {
    const { headers } = await createAuthedUser(request, "lib-list");
    const projectId = await createProject(
      request,
      headers,
      Date.now().toString(),
    );

    // 创建 2 个不同类型的素材库
    await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: `Video Lib ${Date.now()}`,
        kind: "video",
      },
    });
    await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: `Image Lib ${Date.now()}`,
        kind: "image",
      },
    });

    // 列出（按 project_id 过滤）
    const response = await request.get(`${apiBase}/asset-libraries`, {
      headers,
      params: { project_id: projectId },
    });

    expect(
      response.ok(),
      `列出素材库应返回 2xx，实际: ${response.status()} ${await response.text()}`,
    ).toBeTruthy();

    const data = await response.json();
    const items = data.items || [];
    expect(items.length, "应至少有 2 个素材库").toBeGreaterThanOrEqual(2);

    const kinds = items.map((i: { kind: string }) => i.kind);
    expect(kinds).toContain("video");
    expect(kinds).toContain("image");
  });

  test("创建素材记录", async ({ request }) => {
    const { headers, userId } = await createAuthedUser(request, "asset-create");
    const projectId = await createProject(
      request,
      headers,
      Date.now().toString(),
    );

    // 创建素材库
    const lib = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: `Asset Lib ${Date.now()}`,
        kind: "video",
      },
    });
    expect(lib.ok()).toBeTruthy();
    const libData = await lib.json();

    // 创建素材记录
    const response = await request.post(`${apiBase}/assets`, {
      headers,
      data: {
        project_id: projectId,
        library_id: libData.id,
        name: `test_video_${Date.now()}.mp4`,
        storage_key: `uploads/e2e/test_${Date.now()}.mp4`,
        mime_type: "video/mp4",
        metadata: { duration: 15.5, resolution: "1080p" },
        file_size: 1024000,
        status: "ready",
        uploaded_by_user_id: userId,
      },
    });

    expect(
      response.ok(),
      `创建素材应返回 2xx，实际: ${response.status()} ${await response.text()}`,
    ).toBeTruthy();

    const data = await response.json();
    expect(data.id, "应返回素材 ID").toBeTruthy();
    expect(data.name).toContain("test_video");
    expect(data.mime_type).toBe("video/mp4");
    expect(data.library_id).toBe(libData.id);
  });

  test("列出素材", async ({ request }) => {
    const { headers, userId } = await createAuthedUser(request, "asset-list");
    const projectId = await createProject(
      request,
      headers,
      Date.now().toString(),
    );

    // 创建素材库
    const lib = await request.post(`${apiBase}/asset-libraries`, {
      headers,
      data: {
        project_id: projectId,
        name: `List Lib ${Date.now()}`,
        kind: "video",
      },
    });
    expect(lib.ok(), `创建素材库应成功: ${await lib.text()}`).toBeTruthy();
    const libData = await lib.json();

    // 创建 2 个素材
    await request.post(`${apiBase}/assets`, {
      headers,
      data: {
        project_id: projectId,
        library_id: libData.id,
        name: `clip_a_${Date.now()}.mp4`,
        storage_key: `uploads/e2e/clip_a.mp4`,
        mime_type: "video/mp4",
        status: "ready",
        uploaded_by_user_id: userId,
      },
    });
    await request.post(`${apiBase}/assets`, {
      headers,
      data: {
        project_id: projectId,
        library_id: libData.id,
        name: `clip_b_${Date.now()}.mp4`,
        storage_key: `uploads/e2e/clip_b.mp4`,
        mime_type: "video/mp4",
        status: "ready",
        uploaded_by_user_id: userId,
      },
    });

    // 列出素材
    const response = await request.get(`${apiBase}/assets`, {
      headers,
      params: { library_id: libData.id },
    });

    expect(
      response.ok(),
      `列出素材应返回 2xx，实际: ${response.status()} ${await response.text()}`,
    ).toBeTruthy();

    const data = await response.json();
    const items = data.items || [];
    expect(items.length, "应至少有 2 个素材").toBeGreaterThanOrEqual(2);
  });

  test("未登录创建素材库 - 反向", async ({ request }) => {
    const response = await request.post(`${apiBase}/asset-libraries`, {
      data: {
        project_id: "some-project",
        name: "Unauthorized Library",
        kind: "video",
      },
    });

    expect([401, 403]).toContain(response.status());
  });
});
