import { test, expect, waitForHydration, type CDPSession, type Page } from "./fixtures/test";

async function setupVirtualAuthenticator(cdp: CDPSession) {
  await cdp.send("WebAuthn.enable");
  const { authenticatorId } = await cdp.send("WebAuthn.addVirtualAuthenticator", {
    options: {
      protocol: "ctap2",
      transport: "internal",
      hasResidentKey: true,
      hasUserVerification: true,
      isUserVerified: true,
    },
  });
  return authenticatorId;
}

async function registerUser(page: Page, email: string, username: string) {
  await page.goto("/auth/register");
  await expect(page.getByRole("heading", { name: "Register" })).toBeVisible();
  await waitForHydration(page);
  await page.getByLabel("Email").fill(email);
  await page.getByLabel("Username").fill(username);
  await page.getByRole("checkbox").check();
  await page.getByRole("button", { name: /Register with Passkey/ }).click();
  await expect(page).toHaveURL("/", { timeout: 10000 });
}

async function setProfileVisibility(page: Page, value: "public" | "private") {
  await page.goto("/settings");
  await page.locator(`input[type=radio][name=profileVisibility][value=${value}]`).check();
  await page.getByRole("button", { name: /^Save$/ }).first().click();
  // Don't use waitForLoadState("networkidle") — the SSE connection to
  // /api/events keeps the network busy indefinitely. Wait for the
  // explicit save confirmation instead.
  await expect(page.getByText("Profile saved.")).toBeVisible({ timeout: 10000 });
}

test.describe.configure({ mode: "serial" });

test.describe("Notifications", () => {
  test("anonymous /notifications redirects to login", async ({ page }) => {
    await page.goto("/notifications");
    await expect(page).toHaveURL(/\/auth\/login/, { timeout: 10000 });
  });

  test("public auto-accept follow → recipient sees follow_received notification", async ({ page, browser }) => {
    const cdp = await page.context().newCDPSession(page);
    await setupVirtualAuthenticator(cdp);

    const stamp = Date.now();
    const aEmail = `nf-a-${stamp}@example.com`;
    const aUsername = `nfa${stamp}`;
    const bEmail = `nf-b-${stamp}@example.com`;
    const bUsername = `nfb${stamp}`;

    await registerUser(page, aEmail, aUsername);

    const bCtx = await browser.newContext();
    const bPage = await bCtx.newPage();
    const bCdp = await bPage.context().newCDPSession(bPage);
    await setupVirtualAuthenticator(bCdp);
    await registerUser(bPage, bEmail, bUsername);
    await setProfileVisibility(bPage, "public");

    // A follows B (auto-accept).
    await page.goto(`/users/${bUsername}`);
    await waitForHydration(page);
    await page.getByRole("button", { name: "Follow" }).click();
    await expect(page.getByRole("button", { name: "Unfollow" })).toBeVisible({ timeout: 5000 });

    // B opens /notifications — should see one row referencing A.
    await bPage.goto("/notifications");
    await expect(bPage.getByText(new RegExp(`${aUsername}.+started following`))).toBeVisible({ timeout: 10000 });

    // Mark all read clears the unread badge. The button disappears when
    // hasUnread flips to false; the toBeHidden assertion polls.
    await bPage.getByRole("button", { name: /Mark all read/i }).click();
    await expect(bPage.getByRole("button", { name: /Mark all read/i })).toBeHidden({ timeout: 10000 });

    await bCtx.close();
  });

  test("private profile: request → approve → follower sees follow_request_approved notification", async ({ page, browser }) => {
    const cdp = await page.context().newCDPSession(page);
    await setupVirtualAuthenticator(cdp);

    const stamp = Date.now();
    const aEmail = `nfap-a-${stamp}@example.com`;
    const aUsername = `nfapa${stamp}`;
    const bEmail = `nfap-b-${stamp}@example.com`;
    const bUsername = `nfapb${stamp}`;

    await registerUser(page, aEmail, aUsername);

    const bCtx = await browser.newContext();
    const bPage = await bCtx.newPage();
    const bCdp = await bPage.context().newCDPSession(bPage);
    await setupVirtualAuthenticator(bCdp);
    await registerUser(bPage, bEmail, bUsername);
    // B stays private (default).

    // A requests to follow B.
    await page.goto(`/users/${bUsername}`);
    await page.getByRole("button", { name: /Request to follow/i }).click();
    await expect(page.getByRole("button", { name: /Requested/i })).toBeVisible({ timeout: 5000 });

    // B approves the request from the Requests tab on /notifications.
    // After the fetcher.Form revalidates, the empty-state copy
    // replaces the request row.
    await bPage.goto("/notifications?tab=requests");
    await bPage.getByRole("button", { name: "Approve" }).click();
    await expect(bPage.getByText(/No pending follow requests/i)).toBeVisible({ timeout: 10000 });

    // A reloads /notifications — should see follow_request_approved
    // referencing B (the target's username).
    await page.goto("/notifications");
    await expect(page.getByText(new RegExp(`${bUsername}.+accepted your follow request`))).toBeVisible({ timeout: 10000 });

    await bCtx.close();
  });
});
