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

import { mockCoreApis } from "@e2e/fixtures/api-mocks";
import { apiEnvelope } from "@e2e/fixtures/data/common";
import {
  clearBrowserState,
  seedEmailSession,
} from "@e2e/fixtures/test-helpers";

const postId = "11111111-1111-1111-1111-111111111111";
let unlocked = false;

test.beforeEach(async ({ baseURL, context, page }) => {
  unlocked = false;
  await clearBrowserState(context, page, baseURL);
  await mockCoreApis(page);
  await registerPrivateZoneVideoMocks(page);
});

test("Private Zone defaults to Albums and reveals video after switching to Moments", async ({
  page,
}) => {
  await seedEmailSession(page);

  const listRequest = page.waitForRequest((request) => {
    const url = new URL(request.url());
    return (
      url.pathname === "/api/private-zone/posts" &&
      url.searchParams.get("characterId") === "maya-tan"
    );
  });
  await page.goto("/characters/maya/private-zone");
  await listRequest;

  await expect(
    page.getByRole("heading", { name: "Private albums" }),
  ).toBeVisible();
  await expect(page.getByText("Maya archive")).toBeVisible();
  await page.getByRole("tab", { name: "Moments" }).click();
  await expect(
    page.getByRole("heading", { name: "Private moments" }),
  ).toBeVisible();
  await expect(page.getByText("Only for you.")).toBeVisible();
  await expect(page.locator("video")).toHaveCount(0);

  await page.getByRole("button", { name: "Unlock for 100 credits" }).click();
  const dialog = page.getByRole("alertdialog");
  await expect(dialog).toContainText("100 credits");
  const unlockRequest = page.waitForRequest(
    `**/api/private-zone/posts/${postId}/unlock`,
  );
  await dialog.getByRole("button", { name: "Unlock", exact: true }).click();
  expect((await unlockRequest).postDataJSON()).toEqual({ expectedCost: 100 });

  const video = page.locator("video");
  await expect(video).toHaveCount(1);
  await expect(video.locator("source")).toHaveAttribute("src", /video\.mp4/);
  await expect(page.getByRole("alertdialog")).toHaveCount(0);
});

test("Albums render first and Moments remain available behind the second tab", async ({ page }) => {
  await seedEmailSession(page);
  await page.goto("/characters/maya/private-zone");

  const tabs = page.getByRole("tab");
  await expect(tabs).toHaveText(["Albums", "Moments"]);
  await expect(page.getByRole("tab", { name: "Albums" })).toHaveAttribute(
    "aria-selected",
    "true",
  );
  await expect(
    page.getByRole("heading", { name: "Private albums" }),
  ).toBeVisible();
  await expect(page.getByText("Maya archive")).toBeVisible();

  await page.getByRole("tab", { name: "Moments" }).click();
  await expect(page.getByRole("tab", { name: "Moments" })).toHaveAttribute(
    "aria-selected",
    "true",
  );
  await expect(
    page.getByRole("heading", { name: "Private moments" }),
  ).toBeVisible();
});

async function registerPrivateZoneVideoMocks(page: Page): Promise<void> {
  await page.route("**/api/private-zone/posts**", async (route) => {
    const url = new URL(route.request().url());
    await route.fulfill({
      json: apiEnvelope({
        characterId: url.searchParams.get("characterId") ?? "maya-tan",
        items: [videoPost(unlocked)],
        nextCursor: null,
        hasMore: false,
        creditBalance: unlocked ? 150 : 250,
        currency: "credits",
      }),
    });
  });

  // Playwright evaluates page routes in reverse registration order. Register
  // the specific mutation last so the broader list route cannot intercept it.
  await page.route("**/api/private-zone/posts/*/unlock", async (route) => {
    unlocked = true;
    await route.fulfill({
      json: apiEnvelope({
        postId,
        reason: "ok",
        unlocked: true,
        creditsCharged: 100,
        requiredCredits: 100,
        currentCredits: 150,
        shortfallCredits: 0,
        creditBalance: 150,
        post: videoPost(true),
      }),
    });
  });

  await page.route("**/api/private-zone/albums**", async (route) => {
    await route.fulfill({
      json: apiEnvelope({
        items: [
          {
            albumId: "album-maya",
            title: "Maya archive",
            content: null,
            previewText: "Private photos",
            imageCount: 1,
            images: [{ url: "/images/private-zone/banner/maya.png", locked: true, index: 0 }],
            locked: true,
            unlocked: false,
            unlockCost: 80,
            publishedAt: "2026-07-24T10:00:00+00:00",
            lockDetail: { locked: true },
          },
        ],
        creditBalance: 250,
        pendingImageCount: 0,
        hasIncompleteContent: false,
      }),
    });
  });
}

function videoPost(isUnlocked: boolean) {
  return {
    postId,
    characterId: "maya-tan",
    caption: "Only for you.",
    posterUrl: "/images/private-zone/banner/maya.png",
    mediaType: "video",
    videoUrl: isUnlocked ? "/test-video.mp4?token=short" : null,
    videoMimeType: "video/mp4",
    videoSizeBytes: 1024,
    durationSeconds: 18,
    unlockCostCredits: 100,
    currency: "credits",
    locked: !isUnlocked,
    unlocked: isUnlocked,
    availableForNewUnlock: true,
    publishedAt: "2026-07-24T10:00:00+00:00",
  };
}
