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

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

const testPsid = "e2e-facebook-psid-27511427698460020";

const characters = [
  {
    id: "elio",
    slug: "elio",
    displayName: "Elio Silvestri",
    shortName: "Elio",
  },
  {
    id: "maya-tan",
    slug: "maya",
    displayName: "Maya Tan",
    shortName: "Maya",
  },
  {
    id: "nayeli-cervantes",
    slug: "nayeli",
    displayName: "Nayeli Cervantes",
    shortName: "Nayeli",
  },
] as const;

type Character = (typeof characters)[number];
type EntryKind = "private-space" | "voice" | "image-pack" | "coffee";

interface FacebookEntryCase {
  character: Character;
  kind: EntryKind;
  target: "chat" | "private-zone" | "tip";
  expectedPath: string;
  promotionType?: "voice";
}

const entryCases: FacebookEntryCase[] = characters.flatMap((character) => [
  {
    character,
    kind: "private-space",
    target: "chat",
    expectedPath: `/characters/${character.slug}/chat`,
  },
  {
    character,
    kind: "voice",
    target: "chat",
    expectedPath: `/characters/${character.slug}/chat`,
    promotionType: "voice",
  },
  {
    character,
    kind: "image-pack",
    target: "private-zone",
    expectedPath: `/characters/${character.slug}/private-zone`,
  },
  {
    character,
    kind: "coffee",
    target: "tip",
    expectedPath: `/characters/${character.slug}/tip`,
  },
]);

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

for (const entryCase of entryCases) {
  test(`${entryCase.character.displayName} opens Facebook ${entryCase.kind} entry`, async ({
    page,
  }) => {
    await page.goto(buildEntryUrl(entryCase));

    await expect(page).toHaveURL(entryCase.expectedPath, { timeout: 20_000 });
    await expect
      .poll(() =>
        page.evaluate(() => localStorage.getItem("cozsweet:psid")),
      )
      .toBe(testPsid);

    if (entryCase.kind === "private-space") {
      await expect(page.getByRole("textbox", { name: "Message" })).toBeVisible();
      await expect(
        page.getByRole("button", { name: "Unlock voice message" }),
      ).toHaveCount(0);
      return;
    }

    if (entryCase.kind === "voice") {
      await expect(page.getByRole("textbox", { name: "Message" })).toBeVisible();
      await expect(
        page.getByRole("button", { name: "Unlock voice message" }),
      ).toHaveCount(1);
      return;
    }

    if (entryCase.kind === "image-pack") {
      await expect(
        page.getByRole("heading", { name: "Private albums" }),
      ).toBeVisible();
      await expect(
        page.getByText(entryCase.character.displayName).last(),
      ).toBeVisible();
      return;
    }

    await expect(
      page.getByRole("heading", {
        name: `Buy ${entryCase.character.shortName} a coffee`,
      }),
    ).toBeVisible();
  });
}

function buildEntryUrl(entryCase: FacebookEntryCase): string {
  const params = new URLSearchParams({
    target: entryCase.target,
    character: entryCase.character.slug,
    psid: testPsid,
  });
  if (entryCase.promotionType) {
    params.set("mode", "promotion");
    params.set("promotion_type", entryCase.promotionType);
  }
  return `/external-entry?${params.toString()}`;
}

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

  await page.route("**/api/private-zone/albums**", async (route) => {
    await route.fulfill({
      json: apiEnvelope({
        creditBalance: 1000,
        pendingImageCount: 0,
        hasIncompleteContent: false,
        items: [],
      }),
    });
  });

  await page.route("**/api/payment/gift-products**", async (route) => {
    const url = new URL(route.request().url());
    const characterId = url.searchParams.get("characterId") ?? "elio";
    const planPrefix =
      characterId === "elio"
        ? "tip"
        : `tip_${characterId.replaceAll("-", "_")}`;
    await route.fulfill({
      json: apiEnvelope({
        characterId,
        categories: [
          {
            category: "coffee",
            name: "Coffee",
            productCount: 1,
            imageUrl: null,
          },
        ],
        plans: [
          {
            planId: `${planPrefix}_coffee_usd_4_99`,
            planName: "Small Coffee",
            orderType: "tip",
            tipType: "coffee_small",
            category: "coffee",
            characterId,
            description: "A character-scoped coffee gift",
            imageUrl: null,
            amountCents: 499,
            currency: "USD",
            autoRenew: false,
            isFirstRechargeOffer: false,
            firstRechargeDiscountPercent: 0,
            promotionType: null,
          },
        ],
      }),
    });
  });
}
