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

import { e2eEmailUser } from "../data/auth";

export const e2eEmailCredentials = {
  email: "chanwillian0@gmail.com",
  password: "12345678",
};

export const splashStartChatButtonName = "Start Chatting";
export const defaultCharacterSlug = "elio";
export const defaultCharacterSplashPath = `/characters/${defaultCharacterSlug}/splash`;
export const defaultCharacterChatPath = `/characters/${defaultCharacterSlug}/chat`;
export const defaultCharacterProfilePath = `/profile?returnTo=%2Fcharacters%2F${defaultCharacterSlug}%2Fchat`;
export const defaultCharacterChatUrl = new RegExp(
  `/characters/${defaultCharacterSlug}/chat(?:\\?.*)?$`,
);

export function getSplashStartChatButton(page: Page) {
  return page.getByRole("button", { name: splashStartChatButtonName });
}

export async function setEmailSessionStorage(page: Page) {
  await page.evaluate((user) => {
    localStorage.setItem("cozsweet:login_token", "e2e-email-token");
    localStorage.setItem("cozsweet:refresh_token", "e2e-email-refresh-token");
    localStorage.setItem("cozsweet:login_provider", "email");
    localStorage.setItem("cozsweet:user_id", user.id);
    localStorage.setItem("cozsweet:user", JSON.stringify(user));
  }, e2eEmailUser);
}

export async function seedEmailSession(page: Page) {
  await page.goto(defaultCharacterSplashPath);
  await setEmailSessionStorage(page);
  await page.reload();
  // Let the root auth provider hydrate the seeded session before navigation.
  await page.waitForTimeout(750);
}

export async function switchToEmailSignIn(page: Page) {
  const otherOptionsButton = page.getByRole("button", { name: /Other Sign In Options/i });
  const otherOptionsDialog = page.getByRole("dialog", { name: /Other sign-in options/i });
  await expect(otherOptionsButton).toBeVisible({ timeout: 10_000 });
  await expect(otherOptionsButton).toBeEnabled();
  for (let attempt = 0; attempt < 3; attempt += 1) {
    await otherOptionsButton.click();
    try {
      await expect(otherOptionsDialog).toBeVisible({ timeout: 2_000 });
      break;
    } catch (error) {
      if (attempt === 2) throw error;
      await otherOptionsButton.evaluate((button) => (button as HTMLButtonElement).click());
      await page.waitForTimeout(500);
    }
  }
  await page.getByRole("button", { name: "Email Sign In" }).click();
  await expect(page.getByPlaceholder("Email")).toHaveValue(e2eEmailCredentials.email);
  await expect(page.getByPlaceholder("Password")).toHaveValue(e2eEmailCredentials.password);
}

export async function submitEmailLogin(page: Page, options: { expectedUrl?: RegExp; waitForRequest?: boolean; urlTimeout?: number } = {}) {
  const { expectedUrl, waitForRequest = true, urlTimeout = 10_000 } = options;
  const loginButton = page.getByRole("button", { name: "Login" });
  if (!waitForRequest) {
    await Promise.all([expectedUrl ? page.waitForURL(expectedUrl, { timeout: urlTimeout }) : Promise.resolve(), loginButton.click()]);
    return null;
  }
  const loginRequestPromise = page.waitForRequest("**/api/auth/login");
  await loginButton.click();
  const loginRequest = await loginRequestPromise;
  expect(loginRequest.postDataJSON()).toMatchObject({ email: e2eEmailCredentials.email, password: e2eEmailCredentials.password, isTestAccount: true });
  if (expectedUrl) await expect(page).toHaveURL(expectedUrl, { timeout: urlTimeout });
  return loginRequest;
}
