import type { Browser, BrowserContext, Page } from 'playwright';

const PUBLIC_URL = 'https://www.sat.gob.mx/portal/public/tramites/constancia-de-situacion-fiscal';

export interface CsfLoginSession {
  context: BrowserContext;
  appPage: Page;
}

/**
 * Navigates from the public CSF page → "SERVICIO" popup → FIEL login →
 * returns the post-login app page (popup that became the SPA).
 * Ver referencia_sat_portal_csf: el botón "Generar" vive en un iframe JSF
 * dentro de esta appPage, por eso la retornamos tal cual.
 */
export async function loginSatCsf(
  browser: Browser,
  cerPath: string,
  keyPath: string,
  password: string,
): Promise<CsfLoginSession> {
  const context = await browser.newContext({ acceptDownloads: true });
  const publicPage = await context.newPage();
  publicPage.setDefaultTimeout(60_000);

  await publicPage.goto(PUBLIC_URL, { waitUntil: 'networkidle' });
  await publicPage.waitForTimeout(2000);

  // Click acordeón "Obtén tu constancia" / "Obtener constancia"
  const obtenerLocator = publicPage.locator(
    'text=/Obt[eé]n\\s+la\\s+constancia|Obt[eé]n\\s+tu\\s+constancia|Obtener\\s+constancia|Obtener\\s+la\\s+constancia/i',
  ).first();
  await obtenerLocator.waitFor({ state: 'visible', timeout: 60_000 });
  await obtenerLocator.scrollIntoViewIfNeeded();
  await obtenerLocator.click();
  await publicPage.waitForTimeout(1500);

  // Click "SERVICIO" → popup
  const popupPromise = context.waitForEvent('page', { timeout: 60_000 });
  await publicPage.locator('text=/^\\s*SERVICIO\\s*$/i').first().click();
  const loginPage = await popupPromise;
  await loginPage.waitForLoadState('domcontentloaded');
  loginPage.setDefaultTimeout(60_000);

  // Click "e.firma" (NO "e.firma portable"). El SAT a veces aterriza en la
  // pestaña de contraseña: el botón cambia a la vista FIEL. El click sintético
  // de Playwright a veces no dispara el handler — afirmamos el efecto (aparece
  // el file input) y reintentamos con dispatchEvent si hace falta.
  const efirmaBtn = loginPage
    .locator('button:has-text("e.firma"):not(:has-text("portable")), input[type="button"][value="e.firma" i], input[type="submit"][value="e.firma" i]')
    .first();
  await efirmaBtn.waitFor({ state: 'visible', timeout: 30_000 });
  await efirmaBtn.scrollIntoViewIfNeeded();
  await efirmaBtn.click();

  const fileInputs = loginPage.locator('input[type="file"]');
  try {
    await fileInputs.first().waitFor({ state: 'attached', timeout: 10_000 });
  } catch {
    // Retry: el click sintético no disparó el handler — forzamos dispatchEvent
    await efirmaBtn.dispatchEvent('click');
    await fileInputs.first().waitFor({ state: 'attached', timeout: 30_000 });
  }

  // Upload .cer (primer input) y .key (segundo)
  await fileInputs.nth(0).setInputFiles(cerPath);
  await fileInputs.nth(1).setInputFiles(keyPath);

  // Password + Enviar
  await loginPage.locator('input[type="password"]').first().fill(password);
  await loginPage.locator('button:has-text("Enviar"), input[value="Enviar"]').first().click();

  // Esperar a que salga del dominio de login
  await loginPage.waitForURL(url => !url.toString().includes('loginda.siat.sat.gob.mx'), { timeout: 60_000 });
  await loginPage.waitForLoadState('networkidle').catch(() => undefined);
  await loginPage.waitForTimeout(2000);

  const bodyText = await loginPage.locator('body').innerText().catch(() => '');
  if (/contrase[nñ]a\s+incorrecta|usuario.*no.*v[aá]lido|firma\s+inv[aá]lida/i.test(bodyText)) {
    throw new Error('FIEL inválida o contraseña incorrecta');
  }

  return { context, appPage: loginPage };
}
