import { expect, test } from "@playwright/test";
import {
  captureBrowserFailures,
  clickUntilVisible,
  gotoLiveView,
  loginWithMagicLink,
  loginWithPassword,
  projectEmail,
  projectText,
  registerAndConfirm,
  selectOptionContaining,
  waitForMapReady,
} from "./helpers";

test("activity approval, privacy controls, reporting, and moderation work end to end", async ({
  browser,
  request,
}, testInfo) => {
  const projectName = testInfo.project.name;
  const organizerEmail = projectEmail("activity-organizer", projectName);
  const participantEmail = projectEmail("activity-participant", projectName);
  const activityTitle = projectText("E2E public coffee meetup", projectName);
  const organizerMessageText = projectText(
    "Welcome to the E2E activity group.",
    projectName,
  );
  const reportDescription = projectText(
    "E2E moderation evidence for the selected activity message.",
    projectName,
  );
  const proposalTitle = projectText("E2E quiet board games", projectName);
  const fixturePassword = process.env.E2E_FIXTURE_PASSWORD;
  const organizer =
    process.env.E2E_RUN_ID && fixturePassword
      ? await loginWithPassword(browser, organizerEmail, fixturePassword)
      : await registerAndConfirm(
          browser,
          request,
          organizerEmail,
          "E2E Activity Organizer",
        );
  const participant =
    process.env.E2E_RUN_ID && fixturePassword
      ? await loginWithPassword(browser, participantEmail, fixturePassword)
      : await registerAndConfirm(
          browser,
          request,
          participantEmail,
          "E2E Activity Participant",
        );
  const assertOrganizerClean = captureBrowserFailures(organizer.page);
  const assertParticipantClean = captureBrowserFailures(participant.page);

  await gotoLiveView(participant.page, "/moderation");
  await expect(participant.page).toHaveURL(/\/requests$/);
  await expect(participant.page.getByText("Moderator access is required.")).toBeVisible();

  await gotoLiveView(organizer.page, "/activities/new");
  await selectOptionContaining(organizer.page, "Activity type", "Coffee or tea");
  await organizer.page.getByLabel("Preferred setting").selectOption("cafe");
  await organizer.page.getByLabel("Short title").fill(activityTitle);
  await organizer.page
    .getByLabel("Plan and expectations")
    .fill("Meet at a public café for an hour of safe conversation.");

  const startsAt = new Date(Date.now() + 4 * 60 * 60 * 1000).toISOString().slice(0, 16);
  const joinDeadline = new Date(Date.now() + 2 * 60 * 60 * 1000)
    .toISOString()
    .slice(0, 16);
  await organizer.page.getByLabel("Starts at (UTC)").fill(startsAt);
  await organizer.page.getByLabel("Join requests close (UTC)").fill(joinDeadline);
  await organizer.page.getByLabel("Total group capacity").fill("3");
  await organizer.page
    .getByLabel("Approximate public meeting area")
    .fill("E2E central public café");
  await organizer.page.getByLabel("Public map visibility").selectOption("approximate_public");
  await organizer.page.getByLabel("Latitude").fill("50.4501");
  await organizer.page.getByLabel("Longitude").fill("30.5234");
  await organizer.page.locator("#activity-form input[type=checkbox]").check();
  await organizer.page.getByRole("button", { name: "Publish activity" }).click();
  await expect(organizer.page).toHaveURL(/\/activities\/[0-9a-f-]+$/);
  const activityURL = organizer.page.url();

  await gotoLiveView(participant.page, activityURL);
  await expect(participant.page.getByRole("heading", { name: "Approved group chat" })).toHaveCount(
    0,
  );
  await clickUntilVisible(
    participant.page.getByRole("button", { name: "Request to join" }),
    participant.page.getByText("Approval pending"),
  );
  await expect(organizer.page.getByText("E2E Activity Participant")).toBeVisible();

  const organizerControls = organizer.page
    .getByRole("heading", { name: "Organizer controls" })
    .locator("..");
  await organizerControls.getByRole("button", { name: "Approve" }).click();
  await expect(
    participant.page.getByRole("heading", { name: "Approved group chat" }),
  ).toBeVisible();

  await participant.page
    .getByPlaceholder("Message the approved group")
    .fill("I will meet you by the public entrance.");
  await participant.page.getByRole("button", { name: "Send", exact: true }).click();
  await expect(organizer.page.getByText("I will meet you by the public entrance.")).toBeVisible();

  await organizer.page
    .getByPlaceholder("Message the approved group")
    .fill(organizerMessageText);
  await organizer.page.getByRole("button", { name: "Send", exact: true }).click();
  await expect(participant.page.getByText(organizerMessageText)).toBeVisible();

  const organizerMessage = participant.page
    .locator("#activity-messages article")
    .filter({ hasText: organizerMessageText });
  await organizerMessage.getByRole("button", { name: "Report" }).click();
  const safetyControls = participant.page
    .getByRole("heading", { name: "Safety controls" })
    .locator("..");
  await expect(
    safetyControls.getByText("The report is scoped to the selected group message."),
  ).toBeVisible();
  await safetyControls.getByLabel("Reason").selectOption("harassment");
  await safetyControls
    .getByLabel("What happened?")
    .fill(reportDescription);
  await safetyControls.getByRole("button", { name: "Send report" }).click();
  await expect(participant.page.getByText("Report sent to moderators.")).toBeVisible();

  await waitForMapReady(participant.page);
  await gotoLiveView(participant.page, "/categories/proposals");
  await participant.page.getByLabel("Proposed category").fill(proposalTitle);
  await participant.page.getByLabel("Mode").selectOption("activity");
  await participant.page
    .getByLabel("Why is this useful?")
    .fill("A moderated public activity category for quiet board-game meetups.");
  await participant.page.getByRole("button", { name: "Publish proposal" }).click();
  await expect(
    participant.page.getByText("Proposal published for community voting."),
  ).toBeVisible();

  await gotoLiveView(participant.page, activityURL);
  await waitForMapReady(participant.page);
  await participant.page.getByRole("button", { name: "Block organizer" }).click();
  await expect(participant.page).toHaveURL(/\/activities$/);
  await waitForMapReady(participant.page);
  await gotoLiveView(participant.page, "/profile");
  const blockedUsers = participant.page.getByRole("heading", { name: "Blocked users" }).locator("..");
  await expect(blockedUsers.getByText("E2E Activity Organizer")).toBeVisible();
  await blockedUsers.getByRole("button", { name: "Unblock" }).click();
  await expect(participant.page.getByText("User unblocked.")).toBeVisible();

  await participant.page.getByLabel("Default location visibility").selectOption(
    "exact_for_active_match",
  );
  await participant.page
    .getByLabel("Optional external thank-you link")
    .fill("https://example.invalid/e2e-thanks");
  await participant.page.getByRole("button", { name: "Save profile" }).click();
  await expect(participant.page.getByText("Profile updated.")).toBeVisible();

  await participant.page.getByLabel("Network").selectOption("telegram");
  await participant.page.getByLabel("Public profile URL").fill("https://t.me/e2e_participant");
  await participant.page.getByLabel("Handle (optional)").fill("@e2e_participant");
  await participant.page.getByRole("button", { name: "Add unverified link" }).click();
  await expect(participant.page.getByText("Social link added as unverified.")).toBeVisible();
  const socialSection = participant.page
    .getByRole("heading", { name: "Social links" })
    .locator("xpath=ancestor::section");
  await expect(socialSection.getByText("telegram", { exact: true })).toBeVisible();
  await socialSection.getByRole("button", { name: "Remove" }).click();
  await expect(socialSection.getByText("No social links added.")).toBeVisible();

  await gotoLiveView(participant.page, "/requests/new");
  await expect(participant.page.getByLabel("Location visibility")).toHaveValue(
    "exact_for_active_match",
  );

  const adminEmail = process.env.E2E_ADMIN_EMAIL ?? "e2e-admin@example.invalid";
  const admin =
    process.env.E2E_RUN_ID && fixturePassword
      ? await loginWithPassword(browser, adminEmail, fixturePassword)
      : await loginWithMagicLink(browser, request, adminEmail);
  const assertAdminClean = captureBrowserFailures(admin.page);
  await gotoLiveView(admin.page, "/moderation");
  await expect(admin.page.getByRole("heading", { name: "Moderation" })).toBeVisible();

  const reportCard = admin.page
    .locator("article")
    .filter({ hasText: reportDescription });
  await reportCard.getByRole("button", { name: "View scoped evidence" }).click();
  const evidence = admin.page
    .getByRole("heading", { name: "Reported evidence" })
    .locator("xpath=ancestor::section");
  await expect(evidence.getByText(organizerMessageText)).toBeVisible();
  await evidence.getByRole("button", { name: "Close" }).click();
  await reportCard.getByRole("combobox").selectOption("resolved");
  await reportCard.getByPlaceholder("Resolution note").fill("Reviewed in isolated browser E2E.");
  await reportCard.getByRole("button", { name: "Save" }).click();
  await expect(admin.page.getByText("Report updated.")).toBeVisible();

  const proposalCard = admin.page
    .locator("article")
    .filter({ hasText: proposalTitle });
  await proposalCard.getByPlaceholder("Rejection note").fill("Covered by an existing category.");
  await proposalCard.getByRole("button", { name: "Reject" }).click();
  await expect(admin.page.getByText("Proposal rejected.")).toBeVisible();

  const participantRow = admin.page
    .locator("tbody tr")
    .filter({ hasText: participantEmail });
  await participantRow.getByRole("combobox").first().selectOption("restricted");
  await participantRow.getByPlaceholder("Internal note").fill("E2E restriction boundary.");
  await participantRow.getByRole("button", { name: "Save" }).click();
  await expect(admin.page.getByText("User status updated.")).toBeVisible();

  await gotoLiveView(participant.page, "/categories/proposals");
  await participant.page.getByLabel("Proposed category").fill("E2E restricted proposal");
  await participant.page.getByLabel("Mode").selectOption("help");
  await participant.page
    .getByLabel("Why is this useful?")
    .fill("This must be rejected because the account is restricted.");
  await participant.page.getByRole("button", { name: "Publish proposal" }).click();
  await expect(
    participant.page.getByText("Confirm your account and ensure it is active first."),
  ).toBeVisible();

  await waitForMapReady(organizer.page);
  assertOrganizerClean();
  assertParticipantClean();
  assertAdminClean();
  await organizer.context.close();
  await participant.context.close();
  await admin.context.close();
});
