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

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

  test('add module via manual entry shows all required fields', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentWithApplication(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

      if (!result.hasApplication) {
        test.skip(true, 'Could not create application (no active period)');
        return;
      }

      // Wait for subject group page
      const navigation = page.locator('masterev-application-navigation');
      const hasNav = await navigation.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      if (!hasNav) {
        test.skip(true, 'Subject group page not loaded');
        return;
      }

      // Click "Add Module" button
      const addModuleButton = page.locator('p-button').filter({ hasText: /add.*module|modul.*hinzufügen/i }).first();
      await expect(addModuleButton).toBeVisible({ timeout: 5_000 });
      await addModuleButton.click();

      // Wait for dialog (CourseSelectDialog or direct module card)
      const dialog = page.locator('.p-dialog-mask .p-dialog').first();
      const hasDialog = await dialog.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);

      if (!hasDialog) {
        // Some processes skip the dialog and create module cards directly
        const moduleCard = page.locator('masterev-reactive-module-card').first();
        await expect(moduleCard).toBeVisible({ timeout: 5_000 });
        return;
      }

      // CourseSelectDialog is open — look for "manual add" button
      const manualAddButton = dialog.locator('p-button').filter({ hasText: /kurs ändern|add|hinzufügen|manuell/i }).first();
      const hasManualAdd = await manualAddButton.waitFor({ state: 'visible', timeout: 3_000 }).then(() => true).catch(() => false);

      if (hasManualAdd) {
        await manualAddButton.click();

        // CourseAddDialog should now appear
        const addDialog = page.locator('.p-dialog-mask .p-dialog').last();
        await expect(addDialog).toBeVisible({ timeout: 5_000 });

        // Course name field (always required)
        const nameInput = addDialog.locator('input[formcontrolname="name"]');
        await expect(nameInput).toBeVisible({ timeout: 3_000 });

        // Credits field (always present)
        const creditsInput = addDialog.locator('p-inputnumber').first();
        await expect(creditsInput).toBeVisible({ timeout: 3_000 });

        // Course ID field (only if requireCourseId — AS process has this)
        const courseIdInput = addDialog.locator('input[formcontrolname="courseId"]');
        const hasCourseId = await courseIdInput.isVisible({ timeout: 2_000 }).catch(() => false);

        // Fill out the form
        const testName = `E2E Module ${Date.now().toString(36)}`;
        await nameInput.fill(testName);

        if (hasCourseId) {
          await courseIdInput.fill('E2E-COURSE-001');
        }

        // Fill credits
        const creditsNumberInput = addDialog.locator('p-inputnumber input').first();
        await creditsNumberInput.fill('5');

        // SWS field (if visible)
        const hoursInput = addDialog.locator('input[formcontrolname="hours"], p-inputnumber[formcontrolname="hours"] input');
        const hasHours = await hoursInput.first().isVisible({ timeout: 1_000 }).catch(() => false);
        if (hasHours) {
          await hoursInput.first().fill('3');
        }

        // Comment field (if visible)
        const commentInput = addDialog.locator('input[formcontrolname="comment"]');
        const hasComment = await commentInput.isVisible({ timeout: 1_000 }).catch(() => false);
        if (hasComment) {
          await commentInput.fill('E2E test comment');
        }

        // Apply button should be enabled after filling required fields
        const applyButton = addDialog.locator('p-button').filter({ hasText: /apply|anwenden/i }).first();
        await expect(applyButton).toBeVisible({ timeout: 3_000 });

        // Click apply
        await applyButton.locator('button').click();

        // Dialog should close and module card should appear
        await expect(addDialog).not.toBeVisible({ timeout: 5_000 });
        const moduleCard = page.locator('masterev-reactive-module-card');
        await expect(moduleCard.first()).toBeVisible({ timeout: 10_000 });
      }
    } finally {
      await context?.close();
    }
  });

  test('course select dialog shows database courses', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentWithApplication(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

      if (!result.hasApplication) {
        test.skip(true, 'Could not create application (no active period)');
        return;
      }

      const navigation = page.locator('masterev-application-navigation');
      const hasNav = await navigation.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      if (!hasNav) {
        test.skip(true, 'Subject group page not loaded');
        return;
      }

      // Click "Add Module"
      const addModuleButton = page.locator('p-button').filter({ hasText: /add.*module|modul.*hinzufügen/i }).first();
      await expect(addModuleButton).toBeVisible({ timeout: 5_000 });
      await addModuleButton.click();

      // Wait for CourseSelectDialog
      const dialog = page.locator('.p-dialog-mask .p-dialog').first();
      const hasDialog = await dialog.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);

      if (!hasDialog) {
        test.skip(true, 'No CourseSelectDialog (process may not use database)');
        return;
      }

      // Data table with courses should be visible
      const dataTable = dialog.locator('masterev-infinite-data-table, p-table');
      const hasTable = await dataTable.first().waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);

      if (hasTable) {
        // Table should have rows (courses from database)
        const rows = dataTable.first().locator('tr[tabindex]');
        await expect(async () => {
          expect(await rows.count()).toBeGreaterThan(0);
        }).toPass({ timeout: 10_000 });

        // Select first course
        await rows.first().click();

        // "Select course" button should become enabled
        const selectButton = dialog.locator('p-button').filter({ hasText: /kurs wählen|select.*course/i }).first();
        await expect(selectButton).toBeVisible({ timeout: 3_000 });
      }

      // Cancel dialog
      const cancelButton = dialog.locator('p-button').filter({ hasText: /cancel|abbrechen/i }).first();
      await cancelButton.locator('button').click();
      await expect(dialog).not.toBeVisible({ timeout: 5_000 });
    } finally {
      await context?.close();
    }
  });

  test('course ID field is required for AS process', async ({
    browser,
    customerConfig,
    customerName,
  }) => {
    // This test is specific to tum-ed-as where requireCourseId=true
    test.skip(!customerName.includes('tum-ed-as'), 'Course ID only required for AS process');

    let context: { close: () => Promise<void> } | undefined;
    try {
      const result = await createStudentWithApplication(browser, customerConfig, customerName);
      context = result.context;
      const page = result.page;

      if (!result.hasApplication) {
        test.skip(true, 'Could not create application (no active period)');
        return;
      }

      const navigation = page.locator('masterev-application-navigation');
      const hasNav = await navigation.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
      if (!hasNav) {
        test.skip(true, 'Subject group page not loaded');
        return;
      }

      // Add module
      const addModuleButton = page.locator('p-button').filter({ hasText: /add.*module|modul.*hinzufügen/i }).first();
      await expect(addModuleButton).toBeVisible({ timeout: 5_000 });
      await addModuleButton.click();

      // Open manual add dialog
      const selectDialog = page.locator('.p-dialog-mask .p-dialog').first();
      const hasDialog = await selectDialog.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
      if (!hasDialog) {
        test.skip(true, 'No CourseSelectDialog');
        return;
      }

      const manualAddButton = selectDialog.locator('p-button').filter({ hasText: /kurs ändern|add|hinzufügen|manuell/i }).first();
      const hasManualAdd = await manualAddButton.waitFor({ state: 'visible', timeout: 3_000 }).then(() => true).catch(() => false);
      if (!hasManualAdd) {
        test.skip(true, 'No manual add button');
        return;
      }
      await manualAddButton.click();

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

      // Course ID field MUST be visible for AS process
      const courseIdInput = addDialog.locator('input[formcontrolname="courseId"]');
      await expect(courseIdInput).toBeVisible({ timeout: 3_000 });

      // Fill only name and credits (skip courseId) — Apply should stay disabled
      const nameInput = addDialog.locator('input[formcontrolname="name"]');
      await nameInput.fill('E2E Course ID Test');

      const creditsInput = addDialog.locator('p-inputnumber input').first();
      await creditsInput.fill('5');

      // Apply button should be disabled (courseId is empty but required)
      const applyButton = addDialog.locator('p-button').filter({ hasText: /apply|anwenden/i }).first();
      const applyButtonInner = applyButton.locator('button');
      await expect(applyButtonInner).toBeDisabled({ timeout: 2_000 });

      // Now fill course ID — Apply should become enabled
      await courseIdInput.fill('TEST-001');
      await expect(applyButtonInner).toBeEnabled({ timeout: 3_000 });

      // Cancel to clean up
      const cancelButton = addDialog.locator('p-button').filter({ hasText: /cancel|abbrechen/i }).first();
      await cancelButton.locator('button').click();
    } finally {
      await context?.close();
    }
  });
});
