import { test, expect } from '../../fixtures.js';

const DIALOG = '.p-dialog-mask .p-dialog';

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

  test('page loads with table and filters', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    await expect(adminPage).toHaveURL(/\/settings\/students/);

    // Verify p-table is visible (students page uses p-table, not masterev-infinite-data-table)
    await expect(adminPage.locator('p-table, .p-datatable').first()).toBeVisible({ timeout: 10_000 });

    // Verify process filter dropdown
    await expect(adminPage.locator('p-select').first()).toBeVisible({ timeout: 5_000 });

    // Verify search input
    await expect(adminPage.locator('masterev-search-input').first()).toBeVisible({ timeout: 5_000 });
  });

  test('process filter dropdown works', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    await expect(adminPage.locator('p-table, .p-datatable').first()).toBeVisible({ timeout: 10_000 });

    // Click the first p-select (process dropdown)
    const processSelect = adminPage.locator('p-select').first();
    await expect(processSelect).toBeVisible({ timeout: 5_000 });
    await processSelect.click();

    // Verify overlay opens with options
    const option = adminPage.locator('.p-select-overlay .p-select-option').first();
    await expect(option).toBeVisible({ timeout: 5_000 });

    // Capture the option text before selecting
    const optionText = (await option.textContent())!.trim();

    // Click first option to select it
    await option.click();

    // Verify overlay closes
    await expect(adminPage.locator('.p-select-overlay')).not.toBeVisible({ timeout: 5_000 });

    // Verify the selected option text is displayed in the dropdown trigger
    await expect(processSelect).toHaveText(optionText);
  });

  test('application periods button opens dialog', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    await expect(adminPage.locator('p-table, .p-datatable').first()).toBeVisible({ timeout: 10_000 });

    // Click the "Application Periods" / "Bewerbungszeiträume" button
    const periodsButton = adminPage.getByRole('button', { name: /application.*period|bewerbungszeitr/i }).first();
    const hasButton = await periodsButton.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
    if (!hasButton) {
      test.skip(true, 'Application Periods button not found');
      return;
    }
    await periodsButton.click();

    // Verify dialog opens
    const dialog = adminPage.locator(DIALOG).first();
    await expect(dialog).toBeVisible({ timeout: 5_000 });

    // Close dialog
    await adminPage.keyboard.press('Escape');
    await expect(dialog).not.toBeVisible({ timeout: 5_000 });
  });

  test('student table has rows with content', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    const table = adminPage.locator('p-table, .p-datatable').first();
    await expect(table).toBeVisible({ timeout: 10_000 });

    // Wait for loading to finish
    const rows = table.locator('tbody tr');
    const hasRows = await rows.first().waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
    if (!hasRows) {
      test.skip(true, 'No student data rows available');
      return;
    }

    // Verify first row has text content (name column)
    const firstRow = rows.first();
    await expect(firstRow).toHaveText(/.+/);
  });

  test('expand student row shows applications', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    const table = adminPage.locator('p-table, .p-datatable').first();
    await expect(table).toBeVisible({ timeout: 10_000 });

    // Wait for rows
    const chevron = table.locator('tbody .pi-chevron-right').first();
    const hasChevron = await chevron.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
    if (!hasChevron) {
      test.skip(true, 'No expandable student rows available');
      return;
    }

    // Click the expand chevron
    await chevron.click();

    // Verify it changes to expanded state
    await expect(table.locator('tbody .pi-chevron-down').first()).toBeVisible({ timeout: 5_000 });
  });

  test('edit student dialog opens with tabs', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    const table = adminPage.locator('p-table, .p-datatable').first();
    await expect(table).toBeVisible({ timeout: 10_000 });

    // Find and click the edit button on first row
    const editButton = table.locator('[data-testid="edit-button"]').first();
    const hasEdit = await editButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
    if (!hasEdit) {
      test.skip(true, 'No edit button available (no student rows)');
      return;
    }
    await editButton.click();

    // Verify dialog opens
    const dialog = adminPage.locator(DIALOG).first();
    await expect(dialog).toBeVisible({ timeout: 5_000 });

    // Verify tabs are present (Personal Data, Applications, Mails)
    const tabs = dialog.locator('masterev-tabs, [role="tablist"], .p-tabview-nav').first();
    await expect(tabs).toBeVisible({ timeout: 5_000 });

    // Close dialog
    await adminPage.keyboard.press('Escape');
    await expect(dialog).not.toBeVisible({ timeout: 5_000 });
  });

  test('search filters students', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    const table = adminPage.locator('p-table, .p-datatable').first();
    await expect(table).toBeVisible({ timeout: 10_000 });

    const searchInput = adminPage.locator('masterev-search-input input').first();
    await expect(searchInput).toBeVisible({ timeout: 5_000 });
    await searchInput.fill('xyznonexistent');
    await expect(searchInput).toHaveValue('xyznonexistent');
    await searchInput.clear();
  });

  test('period filter dropdown works', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    await expect(adminPage.locator('p-table, .p-datatable').first()).toBeVisible({ timeout: 10_000 });

    // The second p-select is the period filter
    const periodSelect = adminPage.locator('p-select').nth(1);
    const hasPeriod = await periodSelect.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
    test.skip(!hasPeriod, 'Period filter not available');

    await periodSelect.click();

    const option = adminPage.locator('.p-select-overlay .p-select-option').first();
    const hasOption = await option.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
    test.skip(!hasOption, 'No period options available');

    // Capture the option text before selecting
    const optionText = (await option.textContent())!.trim();

    await option.click();
    await expect(adminPage.locator('.p-select-overlay')).not.toBeVisible({ timeout: 5_000 });

    // Verify the selected period text is displayed in the dropdown trigger
    const selectedLabel = periodSelect.locator('.p-select-label');
    await expect(selectedLabel).toHaveText(optionText);
  });

  test('application periods dialog shows tabs and periods', async ({ adminPage }) => {
    await adminPage.goto('/admin/settings/students');
    await expect(adminPage.locator('p-table, .p-datatable').first()).toBeVisible({ timeout: 10_000 });

    const periodsButton = adminPage.getByRole('button', { name: /application.*period|bewerbungszeitr/i }).first();
    const hasButton = await periodsButton.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
    test.skip(!hasButton, 'Application Periods button not found');

    await periodsButton.click();
    const dialog = adminPage.locator(DIALOG).first();
    await expect(dialog).toBeVisible({ timeout: 5_000 });

    // Verify process tabs exist
    const tabs = dialog.locator('[role="tab"]');
    await expect(tabs.first()).toBeVisible({ timeout: 5_000 });

    // Verify accordion panels exist (Past, Current, Next)
    const accordionPanels = dialog.locator('p-accordion-panel');
    const panelCount = await accordionPanels.count();
    expect(panelCount).toBeGreaterThanOrEqual(3);

    // Verify create button exists
    await expect(dialog.locator('[data-testid="create-button"]').first()).toBeVisible({ timeout: 3_000 });

    await adminPage.keyboard.press('Escape');
    await expect(dialog).not.toBeVisible({ timeout: 5_000 });
  });

  // Group edit dialog tests — all require an edit button (i.e. student rows on staging)
  test.describe('student edit dialog', () => {
    test('personal data tab shows name fields and action buttons', async ({ adminPage }) => {
      await adminPage.goto('/admin/settings/students');
      const table = adminPage.locator('p-table, .p-datatable').first();
      await expect(table).toBeVisible({ timeout: 10_000 });

      const editButton = table.locator('[data-testid="edit-button"]').first();
      const hasEdit = await editButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      test.skip(!hasEdit, 'No edit button available (no student rows)');

      await editButton.click();
      const dialog = adminPage.locator(DIALOG).first();
      await expect(dialog).toBeVisible({ timeout: 5_000 });

      // Personal data tab is active by default — verify specific form fields
      await expect(dialog.locator('input[formcontrolname="firstName"]')).toBeVisible({ timeout: 5_000 });
      await expect(dialog.locator('input[formcontrolname="lastName"]')).toBeVisible();
      await expect(dialog.locator('input[formcontrolname="email"]')).toBeVisible();

      // Verify cancel and save buttons
      await expect(dialog.locator('[data-testid="cancel-button"]').first()).toBeVisible();
      await expect(dialog.locator('[data-testid="save-button"]').first()).toBeVisible();

      await dialog.locator('[data-testid="cancel-button"]').first().click();
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    });

    test('applications tab shows content', async ({ adminPage }) => {
      await adminPage.goto('/admin/settings/students');
      const table = adminPage.locator('p-table, .p-datatable').first();
      await expect(table).toBeVisible({ timeout: 10_000 });

      const editButton = table.locator('[data-testid="edit-button"]').first();
      const hasEdit = await editButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      test.skip(!hasEdit, 'No edit button available (no student rows)');

      await editButton.click();
      const dialog = adminPage.locator(DIALOG).first();
      await expect(dialog).toBeVisible({ timeout: 5_000 });

      // Click Applications tab (second tab)
      const tabs = dialog.locator('[role="tab"]');
      await tabs.nth(1).click();

      // Verify content loaded (either application cards or "no applications" message)
      const tabPanel = dialog.locator('masterev-tabpanel').nth(1);
      await expect(tabPanel).toBeVisible({ timeout: 3_000 });

      await dialog.locator('[data-testid="cancel-button"]').first().click();
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    });

    test('mails tab shows mail list', async ({ adminPage }) => {
      await adminPage.goto('/admin/settings/students');
      const table = adminPage.locator('p-table, .p-datatable').first();
      await expect(table).toBeVisible({ timeout: 10_000 });

      const editButton = table.locator('[data-testid="edit-button"]').first();
      const hasEdit = await editButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      test.skip(!hasEdit, 'No edit button available (no student rows)');

      await editButton.click();
      const dialog = adminPage.locator(DIALOG).first();
      await expect(dialog).toBeVisible({ timeout: 5_000 });

      // Click Mails tab (third tab)
      const tabs = dialog.locator('[role="tab"]');
      await tabs.nth(2).click();

      // Verify mail list component loaded
      const mailList = dialog.locator('masterev-mail-sent-list').first();
      await expect(mailList).toBeVisible({ timeout: 5_000 });

      await dialog.locator('[data-testid="cancel-button"]').first().click();
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    });

    test('generate login link produces valid URL', async ({ adminPage }) => {
      await adminPage.goto('/admin/settings/students');
      const table = adminPage.locator('p-table, .p-datatable').first();
      await expect(table).toBeVisible({ timeout: 10_000 });

      const editButton = table.locator('[data-testid="edit-button"]').first();
      const hasEdit = await editButton.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      test.skip(!hasEdit, 'No edit button available (no student rows)');

      await editButton.click();
      const dialog = adminPage.locator(DIALOG).first();
      await expect(dialog).toBeVisible({ timeout: 5_000 });

      // Find the generate login link button
      const linkButton = dialog.locator('button').filter({ hasText: /login.*link|anmeldelink/i }).first();
      const hasLink = await linkButton.waitFor({ state: 'visible', timeout: 3_000 }).then(() => true).catch(() => false);
      test.skip(!hasLink, 'Generate Login Link button not found');

      await linkButton.click();

      // Wait for the generated link input (scoped by aria-label to avoid matching unrelated readonly inputs)
      const linkInput = dialog.locator('input[readonly][aria-label]').first();
      await expect(linkInput).toBeVisible({ timeout: 10_000 });
      const linkValue = await linkInput.inputValue();
      expect(linkValue).toMatch(/^https?:\/\//);

      await dialog.locator('[data-testid="cancel-button"]').first().click();
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    });
  });
});
