import { expect, type Page } from '../fixtures.js';
import { MailpitClient } from './mailpit.js';

const mailpit = new MailpitClient();

/**
 * Create an authenticated student page via magic link flow.
 * Shared helper used across student E2E tests.
 *
 * By default, also fills the auto-opening "complete profile" dialog so subsequent
 * dashboard interactions are not blocked. Pass `completeProfile: false` for tests
 * that explicitly need to assert on the unfilled-profile state.
 */
export async function createStudentPage(
  browser: { newContext: (opts: object) => Promise<{ newPage: () => Promise<Page>; close: () => Promise<void> }> },
  customerConfig: { url: string },
  customerName: string,
  emailPrefix = 'e2e-student',
  options: { completeProfile?: boolean } = {},
): Promise<{ page: Page; context: { close: () => Promise<void> } }> {
  const { completeProfile = true } = options;
  const testEmail = `${emailPrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}@e2e.local`;

  const requestUrl = new URL('/api/actions/auth/magic-link/request', customerConfig.url);
  requestUrl.searchParams.set('redirect_uri', customerConfig.url);
  requestUrl.searchParams.set('customer', customerName);

  const response = await fetch(requestUrl.toString(), {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email: testEmail }),
  });
  if (!response.ok) {
    throw new Error(`Magic link request failed: ${response.status} ${response.statusText}`);
  }

  const email = await mailpit.waitForEmail(testEmail, 15_000);
  const emailDetail = await mailpit.getEmailBody(email.ID);
  const magicLinkUrl = mailpit.extractMagicLinkUrl(emailDetail.HTML);

  const context = await browser.newContext({
    baseURL: customerConfig.url,
    ignoreHTTPSErrors: true,
  });
  const page = await context.newPage();
  await page.goto(magicLinkUrl);
  // Wait for verify to complete: VerifyComponent navigates to /students/application
  // on success. The /students/verify URL also matches /students/, so we must check
  // for /students/application specifically — otherwise the next page.goto() can
  // race and abort the in-flight verify fetch before the session cookie is set.
  await expect(page).toHaveURL(/\/students\/application/, { timeout: 15_000 });

  if (completeProfile) {
    await fillProfileDialog(page);
  }

  return { page, context };
}

/**
 * Fill the auto-opening "Complete profile" dialog with placeholder values
 * and submit it. No-op if the dialog isn't present.
 */
async function fillProfileDialog(page: Page): Promise<void> {
  const dialog = page.locator('.p-dialog-mask .p-dialog').first();
  const isOpen = await dialog.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
  if (!isOpen) return;

  await dialog.locator('input[formcontrolname="firstName"]').fill('E2E');
  await dialog.locator('input[formcontrolname="lastName"]').fill('Student');
  const saveButton = dialog.locator('p-button').filter({ hasText: /save|speichern/i }).locator('button').first();
  await saveButton.click();
  await expect(dialog).not.toBeVisible({ timeout: 5_000 });
}

/**
 * Create an authenticated student and attempt to create a new application.
 * Returns hasApplication=false if no active period is available.
 */
export async function createStudentWithApplication(
  browser: { newContext: (opts: object) => Promise<{ newPage: () => Promise<Page>; close: () => Promise<void> }> },
  customerConfig: { url: string },
  customerName: string,
): Promise<{ page: Page; context: { close: () => Promise<void> }; hasApplication: boolean }> {
  const { page, context } = await createStudentPage(browser, customerConfig, customerName, 'e2e-sg');

  // Navigate to dashboard
  await page.goto(`${customerConfig.url}/students/application`);
  await expect(page).toHaveURL(/\/students/, { timeout: 15_000 });

  // Try to create a new application
  const newAppButton = page.locator('p-button').filter({ hasText: /new.*application|neue.*bewerbung/i }).first();
  const hasButton = await newAppButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);

  if (!hasButton) {
    return { page, context, hasApplication: false };
  }

  await newAppButton.click();
  const dialog = page.locator('.p-dialog-mask .p-dialog').first();
  await expect(dialog).toBeVisible({ timeout: 5_000 });

  // Select first process radio button
  const radioButton = dialog.locator('p-radiobutton').first();
  if (await radioButton.isVisible({ timeout: 2_000 }).catch(() => false)) {
    await radioButton.click();
  }

  // Enter a valid application ID (format: 1-XXXXXXXX, 10 chars)
  const appIdInput = dialog.locator('input[pinputtext], input[formcontrolname="applicationId"]').last();
  await appIdInput.fill(`1-${Date.now().toString().slice(-7)}`);

  // Click create
  const createButton = dialog.locator('p-button').filter({ hasText: /create|erstellen/i }).first();
  const isEnabled = await createButton.locator('button').isEnabled({ timeout: 3_000 }).catch(() => false);
  if (!isEnabled) {
    await page.keyboard.press('Escape');
    return { page, context, hasApplication: false };
  }

  await createButton.locator('button').click();

  // Wait for navigation to subject groups page instead of fixed timeout
  await page.waitForURL(/\/students\/application\//, { timeout: 10_000 }).catch(() => {
    // Fallback: wait for page to stabilize
    return page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {});
  });

  return { page, context, hasApplication: true };
}
