import { test as base, chromium, BrowserContext, Page } from "@playwright/test";
import * as path from "path";
import { dismissAllToasts } from "./element-utils";

/**
 * Custom test fixture que usa un persistent browser context compartido.
 *
 * A diferencia de storageState (que solo guarda cookies + localStorage),
 * un persistent context preserva IndexedDB — donde Element Web guarda
 * las crypto keys de E2EE. Sin esto, cada test ve "Missing session data".
 *
 * El contexto es worker-scoped: se crea una vez y se reutiliza en todos
 * los tests del worker. Esto evita el dialogo "Element is open in another
 * window" que aparece cuando se abre/cierra el contexto repetidamente.
 */

const USER_DATA_DIR = path.resolve(__dirname, "..", ".auth", "chrome-profile");

export const test = base.extend<
  { page: Page },
  { persistentContext: BrowserContext }
>({
  // Worker-scoped: un solo persistent context para todos los tests
  persistentContext: [
    async ({}, use) => {
      const context = await chromium.launchPersistentContext(USER_DATA_DIR, {
        headless: true,
        baseURL: process.env.ELEMENT_URL || "http://localhost:8080",
        viewport: { width: 1280, height: 720 },
      });

      await use(context);
      await context.close();
    },
    { scope: "worker" },
  ],

  // Cada test obtiene una pagina del contexto compartido
  page: async ({ persistentContext }, use) => {
    // Cerrar paginas sobrantes de tests anteriores
    for (const p of persistentContext.pages()) {
      await p.close();
    }
    const page = await persistentContext.newPage();

    await use(page);

    // Cerrar la pagina al finalizar el test
    await page.close();
  },
});

/**
 * Maneja dialogos y toasts de Element que bloquean la carga:
 * - "Element is open in another window" → click Continue
 * - "Missing session data" → error informativo
 * - "Notifications" toast → click Dismiss
 * - "Threads Activity Centre" toast → click OK
 * - Cualquier otro toast → intentar cerrarlo
 *
 * Llamar despues de page.goto("/")
 */
export async function handleElementDialogs(page: Page) {
  // 1. "Element is open in another window" — click Continue
  const continueBtn = page.getByRole("button", { name: "Continue" });
  const hasContinue = await continueBtn
    .waitFor({ state: "visible", timeout: 5_000 })
    .then(() => true)
    .catch(() => false);

  if (hasContinue) {
    console.log("[element] 'Element is open in another window' — clicking Continue");
    await continueBtn.click();
  }

  // 2. "Missing session data" — fatal
  const missingData = page.locator('text="Missing session data"');
  const hasMissing = await missingData
    .waitFor({ state: "visible", timeout: 3_000 })
    .then(() => true)
    .catch(() => false);

  if (hasMissing) {
    throw new Error(
      "Missing session data: crypto keys perdidas. " +
        "Borrar .auth/ y re-ejecutar: rm -rf e2e/.auth && ./dev-scripts/e2e/run.sh"
    );
  }

  // 3. Esperar a que la sidebar aparezca (sesion cargada)
  // Usamos multiples locators porque Element Web cambia la estructura entre versiones
  console.log("[element] Esperando sidebar con rooms...");
  const sidebarLocators = [
    page.locator('[role="tree"][aria-label="Rooms"]'),
    page.locator(".mx_RoomList"),
    page.locator(".mx_LeftPanel_roomListContainer"),
    page.locator('[role="treeitem"]'),
    // Rooms visibles como items en el sidebar
    page.locator(".mx_RoomTile"),
  ];

  let sidebarFound = false;
  for (const locator of sidebarLocators) {
    const visible = await locator.first()
      .waitFor({ state: "visible", timeout: 30_000 })
      .then(() => true)
      .catch(() => false);
    if (visible) {
      console.log("[element] Sidebar visible");
      sidebarFound = true;
      break;
    }
  }

  if (!sidebarFound) {
    // Verificar si estamos en la pagina de login
    const onLoginPage = await page.locator('text="Welcome to Element!"').isVisible().catch(() => false)
      || await page.getByRole("link", { name: "Sign in" }).isVisible().catch(() => false);

    if (onLoginPage) {
      throw new Error(
        "Sesion no cargada: se muestra la pagina de login. " +
          "Borrar .auth/ y re-ejecutar: rm -rf e2e/.auth && ./dev-scripts/e2e/run.sh"
      );
    }

    await page.screenshot({
      path: "test-results/ERROR-no-sidebar.png",
      fullPage: true,
    });
    throw new Error("Sidebar de rooms no encontrado despues de 30s");
  }

  // 4. Cerrar TODOS los toasts que bloquean interacciones
  await dismissAllToasts(page);
}

export { dismissAllToasts } from "./element-utils";
export { expect } from "@playwright/test";
