import { test, expect, Page } from '@playwright/test';

/**
 * E2E Tests: Flujo de Activación de Estudiantes
 * Verifica el flujo completo de activación por código cuando un admin crea un estudiante.
 */

// Helper para simular sesión de admin
async function setAdminSession(page: Page) {
  const mockToken = 'mock.admin.jwt.token';
  const mockUser = {
    id: 1,
    username: 'admin',
    role: 'Admin',
    studentId: null,
    studentName: null,
  };

  await page.evaluate(
    ({ token, user }) => {
      localStorage.setItem('auth_token', token);
      localStorage.setItem('user', JSON.stringify(user));
    },
    { token: mockToken, user: mockUser }
  );
}

test.describe('Activación - Admin Crea Estudiante', () => {
  const timestamp = Date.now();

  test.beforeEach(async ({ page }) => {
    await page.goto('/');
    await setAdminSession(page);
  });

  test('admin debe ver formulario de nuevo estudiante', async ({ page }) => {
    await page.goto('/students/new');

    await expect(
      page.getByRole('heading', { name: /nuevo estudiante/i })
    ).toBeVisible({ timeout: 10000 });

    await expect(page.getByLabel(/nombre/i)).toBeVisible();
    await expect(page.getByLabel(/email/i)).toBeVisible();
  });

  test('debe crear estudiante y mostrar modal de activación', async ({ page }) => {
    await page.goto('/students/new');

    // Llenar formulario
    await page.getByLabel(/nombre/i).fill(`Test Student ${timestamp}`);
    await page.getByLabel(/email/i).fill(`test_${timestamp}@example.com`);

    // Enviar
    await page.getByRole('button', { name: /crear|guardar/i }).click();

    // Debe mostrar modal con código de activación
    await expect(
      page.getByText(/código.*activación|activation.*code/i)
    ).toBeVisible({ timeout: 15000 });

    // Debe mostrar el código generado
    await expect(
      page.locator('[data-testid="activation-code"]').or(
        page.locator('code, .activation-code, .code-display')
      )
    ).toBeVisible();
  });

  test('modal debe mostrar URL de activación', async ({ page }) => {
    await page.goto('/students/new');

    await page.getByLabel(/nombre/i).fill(`Test URL ${timestamp}`);
    await page.getByLabel(/email/i).fill(`testurl_${timestamp}@example.com`);
    await page.getByRole('button', { name: /crear|guardar/i }).click();

    // Esperar modal
    await expect(
      page.getByText(/código.*activación/i)
    ).toBeVisible({ timeout: 15000 });

    // Debe mostrar URL de activación
    await expect(
      page.getByText(/activate\?code=|activar\?codigo=/i)
    ).toBeVisible();
  });

  test('modal debe mostrar fecha de expiración', async ({ page }) => {
    await page.goto('/students/new');

    await page.getByLabel(/nombre/i).fill(`Test Expiry ${timestamp}`);
    await page.getByLabel(/email/i).fill(`testexp_${timestamp}@example.com`);
    await page.getByRole('button', { name: /crear|guardar/i }).click();

    await expect(
      page.getByText(/código.*activación/i)
    ).toBeVisible({ timeout: 15000 });

    // Debe mostrar expiración
    await expect(
      page.getByText(/expira|expiración|válido hasta/i)
    ).toBeVisible();
  });

  test('debe poder copiar código al portapapeles', async ({ page }) => {
    await page.goto('/students/new');

    await page.getByLabel(/nombre/i).fill(`Test Copy ${timestamp}`);
    await page.getByLabel(/email/i).fill(`testcopy_${timestamp}@example.com`);
    await page.getByRole('button', { name: /crear|guardar/i }).click();

    await expect(
      page.getByText(/código.*activación/i)
    ).toBeVisible({ timeout: 15000 });

    // Buscar botón de copiar
    const copyButton = page.getByRole('button', { name: /copiar/i }).or(
      page.locator('[data-testid="copy-code"]')
    );

    if (await copyButton.isVisible()) {
      await copyButton.click();

      // Debe mostrar confirmación de copiado
      await expect(
        page.getByText(/copiado|copied/i)
      ).toBeVisible({ timeout: 5000 }).catch(() => {
        // Puede que el feedback sea diferente
      });
    }
  });

  test('debe cerrar modal y volver al listado', async ({ page }) => {
    await page.goto('/students/new');

    await page.getByLabel(/nombre/i).fill(`Test Close ${timestamp}`);
    await page.getByLabel(/email/i).fill(`testclose_${timestamp}@example.com`);
    await page.getByRole('button', { name: /crear|guardar/i }).click();

    await expect(
      page.getByText(/código.*activación/i)
    ).toBeVisible({ timeout: 15000 });

    // Cerrar modal
    const closeButton = page.getByRole('button', { name: /cerrar|entendido|aceptar|continuar/i });
    await closeButton.click();

    // Debe redirigir al listado o mostrar el listado
    await expect(page).toHaveURL(/\/students|\/admin/);
  });
});

test.describe('Activación - Página de Activación', () => {
  test('debe mostrar página de activación con código válido', async ({ page }) => {
    // Navegar a página de activación con código de prueba
    await page.goto('/activate?code=TESTCODE123');

    // Debe mostrar formulario de activación o error de código inválido
    await expect(
      page.getByText(/activar.*cuenta|bienvenido|código.*inválido|expirado/i)
    ).toBeVisible({ timeout: 10000 });
  });

  test('debe mostrar error con código inválido', async ({ page }) => {
    await page.goto('/activate?code=INVALID');

    // Debe mostrar error
    await expect(
      page.getByText(/inválido|expirado|no encontrado|error/i)
    ).toBeVisible({ timeout: 10000 });
  });

  test('formulario de activación debe tener campos requeridos', async ({ page }) => {
    await page.goto('/activate?code=TESTCODE123');

    // Si el código es válido, debe mostrar formulario
    const usernameField = page.getByLabel(/usuario|username/i);
    const passwordField = page.getByLabel(/contraseña|password/i).first();

    // Si los campos existen (código válido), verificar
    if (await usernameField.isVisible()) {
      await expect(usernameField).toBeVisible();
      await expect(passwordField).toBeVisible();

      // Puede haber campo de confirmar contraseña
      const confirmField = page.getByLabel(/confirmar/i);
      if (await confirmField.isVisible()) {
        await expect(confirmField).toBeVisible();
      }
    }
  });

  test('debe validar usuario único en activación', async ({ page }) => {
    await page.goto('/activate?code=TESTCODE123');

    const usernameField = page.getByLabel(/usuario|username/i);

    if (await usernameField.isVisible()) {
      // Usar un usuario que probablemente exista
      await usernameField.fill('admin');
      await page.getByLabel(/contraseña|password/i).first().fill('Test123!');

      const confirmField = page.getByLabel(/confirmar/i);
      if (await confirmField.isVisible()) {
        await confirmField.fill('Test123!');
      }

      await page.getByRole('button', { name: /activar|crear/i }).click();

      // Debe mostrar error de usuario existente
      await expect(
        page.getByText(/usuario.*existe|ya está en uso|username.*taken/i)
      ).toBeVisible({ timeout: 10000 });
    }
  });

  test('debe validar contraseña mínima en activación', async ({ page }) => {
    await page.goto('/activate?code=TESTCODE123');

    const passwordField = page.getByLabel(/contraseña|password/i).first();

    if (await passwordField.isVisible()) {
      await passwordField.fill('123');
      await page.getByLabel(/usuario|username/i).focus();

      await expect(
        page.getByText(/al menos 6 caracteres|mínimo.*6/i)
      ).toBeVisible();
    }
  });

  test('debe mostrar código de recuperación después de activar', async ({ page }) => {
    const timestamp = Date.now();
    await page.goto('/activate?code=TESTCODE123');

    const usernameField = page.getByLabel(/usuario|username/i);

    if (await usernameField.isVisible()) {
      await usernameField.fill(`newuser_${timestamp}`);
      await page.getByLabel(/contraseña|password/i).first().fill('Test123!');

      const confirmField = page.getByLabel(/confirmar/i);
      if (await confirmField.isVisible()) {
        await confirmField.fill('Test123!');
      }

      await page.getByRole('button', { name: /activar|crear/i }).click();

      // Si la activación es exitosa, debe mostrar código de recuperación
      // o redirigir al dashboard
      await expect(
        page.getByText(/código.*recuperación|recovery.*code|bienvenido|dashboard/i)
      ).toBeVisible({ timeout: 15000 }).catch(() => {
        // Puede redirigir directamente
      });
    }
  });
});

test.describe('Activación - Expiración de Código', () => {
  test('debe mostrar error si código expiró', async ({ page }) => {
    // Código expirado de prueba
    await page.goto('/activate?code=EXPIRED123');

    await expect(
      page.getByText(/expirado|expired|inválido|invalid/i)
    ).toBeVisible({ timeout: 10000 });
  });

  test('admin puede regenerar código para estudiante', async ({ page }) => {
    await page.goto('/');
    await setAdminSession(page);

    // Ir al listado de estudiantes
    await page.goto('/students');

    // Buscar botón de regenerar código (si existe)
    const regenerateButton = page.getByRole('button', { name: /regenerar.*código|nuevo.*código/i });

    if (await regenerateButton.first().isVisible()) {
      await regenerateButton.first().click();

      // Debe mostrar nuevo código
      await expect(
        page.getByText(/nuevo código|código regenerado/i)
      ).toBeVisible({ timeout: 10000 });
    }
  });
});

test.describe('Activación - Flujo Completo', () => {
  test('estudiante activado puede iniciar sesión', async ({ page }) => {
    // Este test asume que hay un estudiante ya activado
    await page.goto('/login');

    // Verificar que el formulario de login funciona
    await expect(page.getByLabel(/usuario/i)).toBeVisible();
    await expect(page.getByLabel(/contraseña/i)).toBeVisible();
    await expect(page.getByRole('button', { name: /iniciar sesión/i })).toBeVisible();
  });

  test('estudiante activado ve su dashboard', async ({ page }) => {
    await page.goto('/');

    // Simular sesión de estudiante activado
    const mockUser = {
      id: 2,
      username: 'activated_student',
      role: 'Student',
      studentId: 10,
      studentName: 'Estudiante Activado',
    };

    await page.evaluate(
      ({ token, user }) => {
        localStorage.setItem('auth_token', token);
        localStorage.setItem('user', JSON.stringify(user));
      },
      { token: 'mock.jwt.token', user: mockUser }
    );

    await page.goto('/dashboard');

    // Debe ver su nombre en el dashboard
    await expect(
      page.getByText(/bienvenido|estudiante/i)
    ).toBeVisible({ timeout: 10000 });
  });

  test('estudiante activado puede inscribirse en materias', async ({ page }) => {
    await page.goto('/');

    const mockUser = {
      id: 2,
      username: 'activated_student',
      role: 'Student',
      studentId: 10,
      studentName: 'Estudiante Activado',
    };

    await page.evaluate(
      ({ token, user }) => {
        localStorage.setItem('auth_token', token);
        localStorage.setItem('user', JSON.stringify(user));
      },
      { token: 'mock.jwt.token', user: mockUser }
    );

    await page.goto('/enrollment/10');

    // Debe ver página de inscripción
    await expect(
      page.getByText(/materias|inscripción/i)
    ).toBeVisible({ timeout: 10000 });
  });
});

test.describe('Activación - Seguridad', () => {
  test('código de activación debe ser de un solo uso', async ({ page }) => {
    // Intentar usar un código ya usado
    await page.goto('/activate?code=USED_CODE_123');

    await expect(
      page.getByText(/ya fue usado|inválido|expirado|no encontrado/i)
    ).toBeVisible({ timeout: 10000 });
  });

  test('página de activación no requiere autenticación', async ({ page }) => {
    // Limpiar sesión
    await page.goto('/');
    await page.evaluate(() => localStorage.clear());

    // Acceder a página de activación
    await page.goto('/activate?code=ANYCODE');

    // No debe redirigir a login
    await expect(page).toHaveURL(/\/activate/);
  });

  test('código de recuperación solo se muestra una vez', async ({ page }) => {
    // Este es más un test de UI - verificar que hay advertencia
    const timestamp = Date.now();
    await page.goto('/activate?code=TESTCODE123');

    const usernameField = page.getByLabel(/usuario|username/i);

    if (await usernameField.isVisible()) {
      await usernameField.fill(`secuser_${timestamp}`);
      await page.getByLabel(/contraseña|password/i).first().fill('Test123!');

      const confirmField = page.getByLabel(/confirmar/i);
      if (await confirmField.isVisible()) {
        await confirmField.fill('Test123!');
      }

      await page.getByRole('button', { name: /activar|crear/i }).click();

      // Si se muestra código de recuperación, debe haber advertencia
      const recoverySection = page.getByText(/código.*recuperación/i);
      if (await recoverySection.isVisible()) {
        await expect(
          page.getByText(/solo.*vez|guarda.*código|importante|advertencia|warning/i)
        ).toBeVisible();
      }
    }
  });
});
