import { expect, test, type Page } from "@playwright/test";
import { createServer, type ViteDevServer } from "vite";
import { mkdirSync } from "node:fs";
import { resolve } from "node:path";

let vite: ViteDevServer;
let webUrl: string;

test.beforeAll(async () => {
  vite = await createServer({
    configFile: resolve("apps/web/vite.config.ts"), root: resolve("apps/web"),
    server: { host: "127.0.0.1", port: 0 },
  });
  await vite.listen();
  const address = vite.httpServer?.address();
  if (!address || typeof address === "string") throw new Error("Vite did not expose a test port.");
  webUrl = `http://127.0.0.1:${address.port}`;
});

test.afterAll(async () => vite.close());

const session = {
  audience: "user", authenticated: true,
  credits: { available_balance: 10, reserved_balance: 0 },
  csrf_token: "csrf-projects-fixture-000000000000000000000000000000000000000",
  expires_at: "2026-08-28T08:00:00.000Z",
  user: { creator_name: "Project User", role: "user", social_id: "@project_user", status: "active", user_id: "00000000-0000-4000-8000-000000000201" },
};

function routeSession(page: Page) {
  return page.route("**/api/v1/auth/session", (route) => route.fulfill({
    body: JSON.stringify(session), contentType: "application/json", status: 200,
  }));
}

async function captureEvidence(page: Page, caseId: string, name: string) {
  const root = process.env.DADA_EVIDENCE_DIR_PROJECTS;
  if (!root) return;
  const directory = resolve(root, caseId, "screenshots");
  mkdirSync(directory, { recursive: true });
  await page.screenshot({ fullPage: true, path: resolve(directory, name) });
}

test("TDD-WP2-PROJ-001 renders the empty WbDYT workspace without inventing a model", async ({ page }) => {
  await routeSession(page);
  await page.route("**/api/v1/projects?status=active", (route) => route.fulfill({
    body: JSON.stringify({ active_count: 0, active_limit: 20, projects: [] }), contentType: "application/json", status: 200,
  }));
  await page.goto(`${webUrl}/app`);

  await expect(page.getByRole("heading", { name: "开始一张新作品" })).toBeVisible();
  await expect(page.getByText("NEW PROJECT", { exact: true })).toBeVisible();
  await expect(page.getByLabel("描述你想生成的画面")).toBeVisible();
  await expect(page.getByRole("radio", { name: "3:4" })).toBeChecked();
  for (const ratio of ["1:1", "4:3", "9:16"]) await expect(page.getByRole("radio", { name: ratio })).toBeVisible();
  await expect(page.getByText("当前没有可用于新任务的模型")).toBeVisible();
  await expect(page.getByRole("button", { name: "生成一张图片" })).toBeDisabled();
  await expect(page.getByText("没有进行中的任务")).toBeVisible();
  await expect(page.getByText("测试数据仅保存在本机，不自动备份，也不会迁移到正式系统。")).toBeVisible();
  await expect(page.getByText("浏览示例模板")).toHaveCount(0);
  await captureEvidence(page, "TDD-WP2-PROJ-001-new-versus-continue", "workspace-empty.png");
});

test("TDD-WP2-PROJ-005 limits failed-empty selection on the project list", async ({ page }) => {
  await page.setViewportSize({ height: 760, width: 375 });
  await routeSession(page);
  const failedId = "00000000-0000-4000-8000-000000000211";
  const successId = "00000000-0000-4000-8000-000000000212";
  await page.route("**/api/v1/projects?status=active", (route) => route.fulfill({
    body: JSON.stringify({
      active_count: 2, active_limit: 20,
      projects: [
        { current_image_id: null, name: "失败草稿", project_id: failedId, ratio: "3:4", state_version: 1, status: "failed_empty", successful_image_count: 0, updated_at: "2026-07-28T08:00:00.000Z" },
        { current_image_id: "00000000-0000-4000-8000-000000000213", name: "城市工作室", project_id: successId, ratio: "3:4", state_version: 2, status: "active", successful_image_count: 1, updated_at: "2026-07-28T08:02:00.000Z" },
      ],
    }), contentType: "application/json", status: 200,
  }));
  let batchPayload: unknown;
  await page.route("**/api/v1/projects/failed-empty/trash", async (route) => {
    batchPayload = route.request().postDataJSON();
    await route.fulfill({
      body: JSON.stringify({ ignored_project_ids: [], trashed_project_ids: [failedId] }), contentType: "application/json", status: 200,
    });
  });
  await page.goto(`${webUrl}/app/projects`);

  await expect(page.getByRole("heading", { name: "项目" })).toBeVisible();
  await expect(page.getByText("2 / 20 active")).toBeVisible();
  await expect(page.getByLabel("选择失败草稿：失败草稿")).toBeVisible();
  await expect(page.getByLabel("选择失败草稿：城市工作室")).toHaveCount(0);
  await page.getByLabel("选择失败草稿：失败草稿").check();
  await page.getByRole("button", { name: "批量移入回收站" }).click();
  expect(batchPayload).toEqual({ project_ids: [failedId] });
  await expect(page.getByText("失败草稿已移入回收站")).toBeVisible();
  expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(375);
  await captureEvidence(page, "TDD-WP2-PROJ-005-failed-draft-retry", "projects-mobile.png");
});

test("TDD-WP2-PROJ-001 keeps ratio fixed and blocks an eleventh image in project detail", async ({ page }) => {
  await routeSession(page);
  const projectId = "00000000-0000-4000-8000-000000000221";
  await page.route(`**/api/v1/projects/${projectId}`, (route) => route.fulfill({
    body: JSON.stringify({
      created_at: "2026-07-28T08:00:00.000Z", current_image_id: "00000000-0000-4000-8000-000000000222",
      draft_prompt: "城市工作室", generations: [], images: Array.from({ length: 10 }, (_, index) => ({
        created_at: `2026-07-28T08:${String(index).padStart(2, "0")}:00.000Z`,
        generation_id: `00000000-0000-4000-8000-${String(223 + index).padStart(12, "0")}`,
        image_id: `00000000-0000-4000-8000-${String(323 + index).padStart(12, "0")}`,
      })),
      name: "城市工作室", project_id: projectId, ratio: "3:4", state_version: 4,
      status: "active", successful_image_count: 10, updated_at: "2026-07-28T08:10:00.000Z",
    }), contentType: "application/json", status: 200,
  }));
  await page.goto(`${webUrl}/app/projects/${projectId}`);

  await expect(page.getByRole("heading", { name: "城市工作室" })).toBeVisible();
  await expect(page.getByText("固定比例 3:4")).toBeVisible();
  await expect(page.getByText("10 / 10 张成功图")).toBeVisible();
  await expect(page.getByRole("button", { name: "继续生成" })).toBeDisabled();
  await expect(page.getByText("请先删除一张非当前底图的历史图")).toBeVisible();
  await expect(page.getByRole("radio")).toHaveCount(0);
  await captureEvidence(page, "TDD-WP2-PROJ-001-new-versus-continue", "project-detail-limit.png");
});
