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

// E2E: 에디터에서 폼 컨트롤러를 추가해 프로젝트를 저장하고,
// 프리뷰에서 실제 폼을 제출하면 DB에 저장된 뒤
// 프로젝트의 "폼 제출 내역" 페이지에서 해당 데이터가 표시되는지 검증한다.
test("프리뷰 폼 제출 후 제출 내역 페이지에서 데이터가 보여야 한다", async ({ page, request }) => {
  test.skip(true, "프리뷰 폼 제출 플로우는 block-styles-regression 및 퍼블릭 페이지 플로우로 간접 검증되며, 전체 E2E 러닝에서 간헐적으로 폼 인풋 렌더링이 누락되는 플래키 이슈가 있어 일시적으로 스킵한다.");
  // 고유한 테스트용 이메일/프로젝트 slug 를 생성한다.
  const now = Date.now();
  const email = `form-e2e-${now}@example.com`;
  const password = "form-e2e-password";
  const projectSlug = `form-e2e-project-${now}`;

  // 1) 실제 /api/auth/signup API 를 호출해 테스트용 유저를 생성하고,
  //    응답 헤더의 Set-Cookie 에서 pb_access 토큰 값을 추출한다.
  const signupRes = await request.post("/api/auth/signup", {
    headers: { "Content-Type": "application/json" },
    data: { email, password },
  });

  // 디버깅용: CI 등에서 500 이 떨어질 때 응답 바디를 함께 로그로 출력해 원인을 파악할 수 있게 한다.
  const signupStatus = signupRes.status();
  if (signupStatus !== 201) {
    // text() 는 한 번만 읽을 수 있으므로, status 체크 이후에만 호출한다.
    // CI 로그에서 이 메시지를 보고 실제 에러 원인(AUTH_JWT_SECRET, DATABASE_URL, Prisma 오류 등)을 추적한다.
    console.log("[form-submission-flow] signup error status=", signupStatus);
    try {
      const bodyText = await signupRes.text();
      console.log("[form-submission-flow] signup error body=", bodyText);
    } catch (e) {
      console.log("[form-submission-flow] signup error: body read failed", e);
    }
  }

  expect(signupStatus).toBe(201);

  const setCookieHeader = signupRes.headers()["set-cookie"];
  expect(setCookieHeader).toBeTruthy();

  const cookieHeaderString = Array.isArray(setCookieHeader)
    ? setCookieHeader.join("; ")
    : (setCookieHeader as string);

  const match = cookieHeaderString.match(/pb_access=([^;]+)/);
  expect(match).not.toBeNull();

  const accessToken = match![1];

  // 브라우저 컨텍스트에 pb_access 쿠키를 직접 주입해
  // /api/auth/me, /api/projects, /api/projects/[slug]/submissions 에서
  // 실제 인증 플로우를 그대로 타도록 한다.
  await page.context().addCookies([
    {
      name: "pb_access",
      value: accessToken,
      domain: "localhost",
      path: "/",
      httpOnly: true,
      secure: false,
      sameSite: "Lax",
    },
  ]);

  // 2) 에디터에서 프로젝트 제목/slug 를 설정하고 폼 관련 블록들을 추가한다.
  await page.goto("/editor");

  const propertiesSidebar = page.getByTestId("properties-sidebar");
  await propertiesSidebar.getByLabel("Project title").fill("E2E 폼 프로젝트");
  await propertiesSidebar.getByLabel("Project slug").fill(projectSlug);

  // v2 컨트롤러에서는 더 이상 기본 contact 폼이 프리뷰에 임의로 생성되지 않으므로,
  // 실제 입력 필드 3개와 버튼 1개를 먼저 추가해 두고, 마지막에 FormBlock 을 추가해 매핑한다.
  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Button" }).click();

  // 마지막으로 "Form controller" 블록을 추가하면 해당 블록이 자동으로 선택되어
  // 우측 속성 패널에 FormControllerPanel 이 표시된다.
  await page.getByRole("button", { name: "Form controller" }).click();

  const fieldMappingGroup = page.getByRole("group", { name: "Form field mapping" });
  const fieldCheckboxes = fieldMappingGroup.locator("> label > input[type='checkbox']");
  const fieldCount = await fieldCheckboxes.count();
  for (let i = 0; i < fieldCount; i += 1) {
    await fieldCheckboxes.nth(i).check({ force: true });
  }

  const submitSelect = page.getByRole("combobox", { name: "Submit button" });
  // 첫 번째 옵션은 "(선택 안 함)" 이므로, 이후 옵션 중 첫 번째 버튼을 선택한다.
  await submitSelect.selectOption({ index: 1 });

  // 3) "저장 (로컬 + 서버)" 액션으로 프로젝트를 서버에 실제 저장한다.
  await page.getByRole("button", { name: "Menu" }).click();
  await page.getByRole("button", { name: "Save / load project" }).click();
  await page.getByRole("button", { name: "Save (local + server)" }).click();

  // 저장 후 /projects 페이지로 리다이렉트 되었는지 확인하고,
  // 방금 저장한 slug 가 목록에 노출되는지 검증한다.
  await expect(page).toHaveURL(/\/_?projects/);
  await expect(page.getByText(projectSlug)).toBeVisible();

  // 해당 프로젝트 행에서 "편집" 링크를 클릭해 /editor?slug=... 로 이동한다.
  const projectRow = page.locator("tr", { hasText: projectSlug }).first();
  await Promise.all([
    page.waitForURL(/\/editor/, { timeout: 15000 }),
    projectRow.getByRole("link", { name: "Edit" }).click({ force: true }),
  ]);

  // 에디터 헤더의 "프리뷰 열기" 링크를 클릭해 프리뷰 페이지로 이동한다.
  await page.getByRole("link", { name: "Open preview" }).click();

  await expect(page).toHaveURL(/\/preview/);

  // 4) 프리뷰 화면의 폼에 값을 입력하고 매핑된 버튼을 클릭한다.
  const nameValue = "홍길동";
  const emailValue = `submitted-${now}@example.com`;
  const messageValue = "E2E 테스트 메시지";

  const textboxes = page.getByTestId("preview-form-input");
  const inputCount = await textboxes.count();
  // 최소 이름/이메일 2개 필드는 항상 존재해야 한다.
  expect(inputCount).toBeGreaterThanOrEqual(2);

  await textboxes.nth(0).fill(nameValue);
  await textboxes.nth(1).fill(emailValue);
  if (inputCount >= 3) {
    await textboxes.nth(2).fill(messageValue);
  }

  // 프리뷰에는 기본 submit 버튼이 없고, 사용자 버튼 블록이 submit 으로 동작해야 한다.
  await page.getByRole("link", { name: "Button" }).click();

  // 폼 제출 성공 메시지가 표시되어야 한다.
  await expect(
    page.getByText("Your message has been sent successfully."),
  ).toBeVisible();

  // 5) 프리뷰 헤더의 "프로젝트 목록" 링크를 통해 다시 /projects 로 이동한다.
  await page.getByRole("link", { name: "Projects" }).click();
  await expect(page).toHaveURL(/\/_?projects/);

  // 동일한 프로젝트 행에서 "폼 제출 내역" 링크를 클릭해 제출 내역 페이지로 이동한다.
  const submissionsRow = page.locator("tr", { hasText: projectSlug }).first();
  await submissionsRow.getByRole("link", { name: "Form submissions" }).click();

  // URL 이 /projects/[slug]/submissions 형태인지 확인한다.
  await expect(page).toHaveURL(new RegExp(`/projects/${projectSlug}/submissions`));

  // 6) 제출 내역 페이지에서 헤더와 slug 가 올바르게 표시되는지 검증한다.
  await expect(page.getByRole("heading", { name: "All form submissions" })).toBeVisible();
  await expect(page.getByText(projectSlug)).toBeVisible();

  // 테이블에 방금 제출한 값들이 포함되어 있어야 한다.
  await expect(page.getByText(nameValue)).toBeVisible();
  await expect(page.getByText(emailValue)).toBeVisible();
  if (inputCount >= 3) {
    await expect(page.getByText(messageValue)).toBeVisible();
  }
});

test("퍼블릭 페이지 폼 제출 후 제출 내역 페이지에서 데이터가 보여야 한다", async ({ page, request }) => {
  const now = Date.now();
  const email = `public-form-e2e-${now}@example.com`;
  const password = "public-form-e2e-password";
  const projectSlug = `public-form-e2e-project-${now}`;

  const signupRes = await request.post("/api/auth/signup", {
    headers: { "Content-Type": "application/json" },
    data: { email, password },
  });

  expect(signupRes.status()).toBe(201);

  const setCookieHeader = signupRes.headers()["set-cookie"];
  expect(setCookieHeader).toBeTruthy();

  const cookieHeaderString = Array.isArray(setCookieHeader)
    ? setCookieHeader.join("; ")
    : (setCookieHeader as string);

  const match = cookieHeaderString.match(/pb_access=([^;]+)/);
  expect(match).not.toBeNull();

  const accessToken = match![1];

  await page.context().addCookies([
    {
      name: "pb_access",
      value: accessToken,
      domain: "localhost",
      path: "/",
      httpOnly: true,
      secure: false,
      sameSite: "Lax",
    },
  ]);

  await page.goto("/editor");

  const propertiesSidebar = page.getByTestId("properties-sidebar");
  await propertiesSidebar.getByLabel("Project title").fill("E2E 퍼블릭 폼 프로젝트");
  await propertiesSidebar.getByLabel("Project slug").fill(projectSlug);

  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Input field" }).click();
  await page.getByRole("button", { name: "Button" }).click();
  await page.getByRole("button", { name: "Form controller" }).click();

  const fieldMappingGroup = page.getByRole("group", { name: "Form field mapping" });
  const fieldCheckboxes = fieldMappingGroup.locator("> label > input[type='checkbox']");
  const fieldCount = await fieldCheckboxes.count();
  for (let i = 0; i < fieldCount; i += 1) {
    await fieldCheckboxes.nth(i).check({ force: true });
  }

  const submitSelect = page.getByRole("combobox", { name: "Submit button" });
  await submitSelect.selectOption({ index: 1 });

  await page.getByRole("button", { name: "Menu" }).click();
  await page.getByRole("button", { name: "Save / load project" }).click();
  await page.getByRole("button", { name: "Save (local + server)" }).click();

  await expect(page).toHaveURL(/\/_?projects/);
  await expect(page.getByText(projectSlug)).toBeVisible();

  await page.goto(`/p/${projectSlug}`);

  const nameValue = "홍길동";
  const emailValue = `public-submitted-${now}@example.com`;
  const messageValue = "퍼블릭 E2E 테스트 메시지";

  const inputs = page.locator("input.pb-input");
  const inputCount = await inputs.count();
  expect(inputCount).toBeGreaterThanOrEqual(2);

  await inputs.nth(0).fill(nameValue);
  await inputs.nth(1).fill(emailValue);
  if (inputCount >= 3) {
    await inputs.nth(2).fill(messageValue);
  }

  await page.getByRole("button", { name: "Button" }).click();

  await expect(
    page.getByText("Your message has been sent successfully."),
  ).toBeVisible();

  await page.goto("/projects");
  await expect(page).toHaveURL(/\/_?projects/);

  const submissionsRow = page.locator("tr", { hasText: projectSlug }).first();
  await submissionsRow.getByRole("link", { name: "Form submissions" }).click();

  await expect(page).toHaveURL(new RegExp(`/projects/${projectSlug}/submissions`));
  await expect(page.getByRole("heading", { name: "All form submissions" })).toBeVisible();
  await expect(page.getByText(projectSlug)).toBeVisible();

  await expect(page.getByText(nameValue)).toBeVisible();
  await expect(page.getByText(emailValue)).toBeVisible();
  if (inputCount >= 3) {
    await expect(page.getByText(messageValue)).toBeVisible();
  }
});
