import { test, expect } from '../../fixtures.js';
import { convexRun } from '../../helpers/convex.js';
import { createStudentPage } from '../../helpers/students.js';

/**
 * Seed an open application period so the "New Application" button is
 * guaranteed to render. "No active phase" is a data condition we control,
 * not a legitimate skip.
 */
async function seedOpenPeriod(
  customerName: string,
  firstProcess: string | undefined,
): Promise<void> {
  if (!firstProcess) {
    throw new Error(
      `Customer ${customerName} has students enabled but no firstProcess configured — cannot seed an application period.`,
    );
  }
  await convexRun('e2e:ensureOpenApplicationPeriod', {
    customer: customerName,
    process: firstProcess,
    short: 'E2E',
  });
}

test.describe('Students: Dashboard', () => {
  test.beforeEach(({ features }) => {
    test.skip(!features.students, 'Students feature not enabled');
  });

  test('new student sees profile completion prompt', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentPage(
        browser,
        customerConfig,
        customerName,
        'e2e-student',
        { completeProfile: false },
      );
      context = result.context;
      const page = result.page;

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

      // New student should see profile incomplete warning or profile dialog
      const profileWarning = page.locator('p-message[severity="warn"]').first();
      const profileDialog = page.locator('.p-dialog').first();
      const hasWarning = await profileWarning.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      const hasDialog = await profileDialog.waitFor({ state: 'visible', timeout: 3_000 }).then(() => true).catch(() => false);

      expect(hasWarning || hasDialog).toBeTruthy();
    } finally {
      await context?.close();
    }
  });

  test('dashboard shows greeting', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentPage(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

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

      // Dashboard should show a greeting (h1)
      const greeting = page.locator('h1').first();
      await expect(greeting).toBeVisible({ timeout: 10_000 });
      await expect(greeting).toHaveText(/.+/);
    } finally {
      await context?.close();
    }
  });

  test('empty dashboard shows info message', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentPage(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

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

      // New student has no applications - should see info/warn message
      const message = page.locator('p-message').first();
      await expect(message).toBeVisible({ timeout: 10_000 });
    } finally {
      await context?.close();
    }
  });

  test('new application button opens dialog', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      await seedOpenPeriod(customerName, customerConfig.firstProcess);
      const result = await createStudentPage(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

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

      // The period is seeded, so the "New Application" button MUST render.
      const newAppButton = page.locator('p-button').filter({ hasText: /new.*application|neue.*bewerbung/i }).first();
      await expect(
        newAppButton,
        'new-application button must render (period is seeded)',
      ).toBeVisible({ timeout: 15_000 });

      await newAppButton.click();

      // Dialog should open with process radio buttons and application ID input
      const dialog = page.locator('.p-dialog-mask .p-dialog').first();
      await expect(dialog).toBeVisible({ timeout: 5_000 });

      // Should have application ID input
      const appIdInput = dialog.locator('input[formcontrolname="applicationId"], input').last();
      await expect(appIdInput).toBeVisible({ timeout: 5_000 });

      // Close dialog
      await page.keyboard.press('Escape');
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    } finally {
      await context?.close();
    }
  });

  test('create button disabled with invalid application ID', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      await seedOpenPeriod(customerName, customerConfig.firstProcess);
      const result = await createStudentPage(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

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

      // The period is seeded, so the "New Application" button MUST render.
      const newAppButton = page.locator('p-button').filter({ hasText: /new.*application|neue.*bewerbung/i }).first();
      await expect(
        newAppButton,
        'new-application button must render (period is seeded)',
      ).toBeVisible({ timeout: 15_000 });
      await newAppButton.click();

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

      // Create button should be disabled when form is invalid
      const createButton = dialog.locator('p-button').filter({ hasText: /create|erstellen/i }).first();
      await expect(createButton.locator('button')).toBeDisabled();

      // Enter too short application ID
      const appIdInput = dialog.locator('input[formcontrolname="applicationId"], input[pinputtext]').last();
      await appIdInput.fill('12345');

      // Create button should still be disabled
      await expect(createButton.locator('button')).toBeDisabled();

      await page.keyboard.press('Escape');
    } finally {
      await context?.close();
    }
  });
});
