import { test, expect } from '@playwright/test';
import { runSql, clearCache, resolveDeterministicIds, createTestUser } from './helpers';

const baseUrl = process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:4173';
const urlMatch = baseUrl.match(/:(\d+)$/);
const PORT = urlMatch ? urlMatch[1] : '4173';
const ALPHA_URL = `http://ecole-alpha.classeo.local:${PORT}`;

const TEACHER_EMAIL = 'e2e-eval-teacher@example.com';
const TEACHER_PASSWORD = 'EvalTest123';
const TENANT_ID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';

async function loginAsTeacher(page: import('@playwright/test').Page) {
	await page.goto(`${ALPHA_URL}/login`);
	await page.locator('#email').fill(TEACHER_EMAIL);
	await page.locator('#password').fill(TEACHER_PASSWORD);
	await Promise.all([
		page.waitForURL(/\/dashboard/, { timeout: 60000 }),
		page.getByRole('button', { name: /se connecter/i }).click()
	]);
}

async function navigateToEvaluations(page: import('@playwright/test').Page) {
	await page.goto(`${ALPHA_URL}/dashboard/teacher/evaluations`);
	await expect(page.getByRole('heading', { name: /mes évaluations/i })).toBeVisible({ timeout: 15000 });
}

async function selectClassAndSubject(page: import('@playwright/test').Page) {
	const classSelect = page.locator('#ev-class');
	await expect(classSelect).toBeVisible();
	await classSelect.selectOption({ index: 1 });

	// Wait for subject options to appear after class selection
	const subjectSelect = page.locator('#ev-subject');
	await expect(subjectSelect).toBeEnabled({ timeout: 5000 });
	await expect(subjectSelect.locator('option')).not.toHaveCount(1, { timeout: 10000 });
	await subjectSelect.selectOption({ index: 1 });
}

function seedTeacherAssignments() {
	const { academicYearId } = resolveDeterministicIds(TENANT_ID);
	try {
		runSql(
			`INSERT INTO teacher_assignments (id, tenant_id, teacher_id, school_class_id, subject_id, academic_year_id, status, start_date, created_at, updated_at) ` +
				`SELECT gen_random_uuid(), '${TENANT_ID}', u.id, c.id, s.id, '${academicYearId}', 'active', NOW(), NOW(), NOW() ` +
				`FROM users u CROSS JOIN school_classes c CROSS JOIN subjects s ` +
				`WHERE u.email = '${TEACHER_EMAIL}' AND u.tenant_id = '${TENANT_ID}' ` +
				`AND c.tenant_id = '${TENANT_ID}' ` +
				`AND s.tenant_id = '${TENANT_ID}' ` +
				`ON CONFLICT DO NOTHING`
		);
	} catch {
		// Table may not exist
	}
}

test.describe('Evaluation Management (Story 6.1)', () => {
	test.beforeAll(async () => {
		// Create teacher user
		createTestUser('ecole-alpha', TEACHER_EMAIL, TEACHER_PASSWORD, 'ROLE_PROF');

		// Ensure classes and subject exist
		const { schoolId, academicYearId } = resolveDeterministicIds(TENANT_ID);
		try {
			runSql(
				`INSERT INTO school_classes (id, tenant_id, school_id, academic_year_id, name, level, status, created_at, updated_at) ` +
					`VALUES (gen_random_uuid(), '${TENANT_ID}', '${schoolId}', '${academicYearId}', 'E2E-EVAL-6A', '6ème', 'active', NOW(), NOW()) ON CONFLICT DO NOTHING`
			);
			runSql(
				`INSERT INTO subjects (id, tenant_id, school_id, name, code, status, created_at, updated_at) ` +
					`VALUES (gen_random_uuid(), '${TENANT_ID}', '${schoolId}', 'E2E-EVAL-Maths', 'E2EVALM', 'active', NOW(), NOW()) ON CONFLICT DO NOTHING`
			);
		} catch {
			// May already exist
		}

		seedTeacherAssignments();
		clearCache();
	});

	test.beforeEach(async () => {
		// Clean up ALL evaluations for this teacher (not just by tenant, to avoid
		// stale data from parallel test files with different teachers)
		try {
			runSql(`DELETE FROM grade_events WHERE grade_id IN (SELECT g.id FROM grades g JOIN evaluations e ON g.evaluation_id = e.id WHERE e.tenant_id = '${TENANT_ID}' AND e.teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}'))`);
			runSql(`DELETE FROM grades WHERE evaluation_id IN (SELECT id FROM evaluations WHERE tenant_id = '${TENANT_ID}' AND teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}'))`);
			runSql(`DELETE FROM evaluations WHERE tenant_id = '${TENANT_ID}' AND teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}')`);
		} catch {
			// Table may not exist
		}

		const { schoolId: sId, academicYearId: ayId } = resolveDeterministicIds(TENANT_ID);
		try {
			runSql(
				`INSERT INTO school_classes (id, tenant_id, school_id, academic_year_id, name, level, status, created_at, updated_at) ` +
					`VALUES (gen_random_uuid(), '${TENANT_ID}', '${sId}', '${ayId}', 'E2E-EVAL-6A', '6ème', 'active', NOW(), NOW()) ON CONFLICT DO NOTHING`
			);
			runSql(
				`INSERT INTO subjects (id, tenant_id, school_id, name, code, status, created_at, updated_at) ` +
					`VALUES (gen_random_uuid(), '${TENANT_ID}', '${sId}', 'E2E-EVAL-Maths', 'E2EVALM', 'active', NOW(), NOW()) ON CONFLICT DO NOTHING`
			);
		} catch {
			// May already exist
		}

		seedTeacherAssignments();
		clearCache();
	});

	// ============================================================================
	// Navigation
	// ============================================================================
	test.describe('Navigation', () => {
		test('evaluations link appears in teacher navigation', async ({ page }) => {
			await loginAsTeacher(page);
			const nav = page.locator('.desktop-nav');
			await expect(nav.getByRole('link', { name: /évaluations/i })).toBeVisible({ timeout: 15000 });
		});

		test('can navigate to evaluations page', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);
			await expect(page.getByRole('heading', { name: /mes évaluations/i })).toBeVisible();
		});
	});

	// ============================================================================
	// Empty State
	// ============================================================================
	test.describe('Empty State', () => {
		test('shows empty state when no evaluations exist', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);
			await expect(page.getByText(/aucune évaluation/i)).toBeVisible({ timeout: 10000 });
		});
	});

	// ============================================================================
	// AC1-AC5: Create Evaluation
	// ============================================================================
	test.describe('AC1-AC5: Create Evaluation', () => {
		test('can create a new evaluation with default grade scale and coefficient', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Open create modal
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });

			// Select class and subject
			await selectClassAndSubject(page);

			// Fill title
			await page.locator('#ev-title').fill('Contrôle chapitre 5');

			// Fill date
			await page.locator('#ev-date').fill('2026-06-15');

			// Submit
			await page.getByRole('button', { name: 'Créer', exact: true }).click();

			// Wait for modal to close (creation succeeded)
			await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15000 });

			// Verify evaluation appears in list
			await expect(page.getByText('Contrôle chapitre 5')).toBeVisible({ timeout: 10000 });
			// Verify default grade scale and coefficient badges
			await expect(page.getByText('/20')).toBeVisible();
			await expect(page.getByText('x1')).toBeVisible();
		});

		test('can create evaluation with custom grade scale and coefficient', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });

			// Select class and subject
			await selectClassAndSubject(page);

			// Fill form
			await page.locator('#ev-title').fill('QCM rapide');
			await page.locator('#ev-date').fill('2026-06-20');

			// Set custom grade scale /10
			await page.locator('#ev-scale').fill('10');

			// Set coefficient to 0.5
			await page.locator('#ev-coeff').fill('0.5');

			// Submit
			await page.getByRole('button', { name: 'Créer', exact: true }).click();

			// Verify evaluation with custom values
			await expect(page.getByText('QCM rapide')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('/10')).toBeVisible();
			await expect(page.getByText('x0.5')).toBeVisible();
		});
	});

	// ============================================================================
	// AC6: Edit Evaluation
	// ============================================================================
	test.describe('AC6: Edit Evaluation', () => {
		test('can modify title, description, and coefficient', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Create an evaluation first
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			await selectClassAndSubject(page);
			await page.locator('#ev-title').fill('Évaluation originale');
			await page.locator('#ev-date').fill('2026-06-15');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByText('Évaluation originale')).toBeVisible({ timeout: 10000 });

			// Open edit modal
			await page.getByRole('button', { name: /modifier/i }).first().click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });

			// Modify title
			await page.locator('#edit-title').fill('Évaluation modifiée');

			// Modify coefficient
			await page.locator('#edit-coeff').fill('2');

			// Submit
			await page.getByRole('button', { name: /enregistrer/i }).click();

			// Verify changes
			await expect(page.getByText('Évaluation modifiée')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('x2')).toBeVisible();
		});
	});

	// ============================================================================
	// Delete Evaluation
	// ============================================================================
	test.describe('Delete Evaluation', () => {
		test('can delete an evaluation', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Create an evaluation first
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			await selectClassAndSubject(page);
			await page.locator('#ev-title').fill('Évaluation à supprimer');
			await page.locator('#ev-date').fill('2026-06-15');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByText('Évaluation à supprimer')).toBeVisible({ timeout: 10000 });

			// Open delete modal
			await page.getByRole('button', { name: /supprimer/i }).first().click();
			await expect(page.getByRole('alertdialog')).toBeVisible({ timeout: 10000 });

			// Confirm deletion
			await page.getByRole('alertdialog').getByRole('button', { name: /supprimer/i }).click();

			// Verify evaluation is removed
			await expect(page.getByText(/aucune évaluation/i)).toBeVisible({ timeout: 10000 });
		});
	});

	// ============================================================================
	// T1: Search evaluations by title (P2)
	// ============================================================================
	test.describe('Search evaluations', () => {
		test('filters evaluations when searching by title', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Create first evaluation: "Contrôle géométrie"
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			await selectClassAndSubject(page);
			await page.locator('#ev-title').fill('Contrôle géométrie');
			await page.locator('#ev-date').fill('2026-06-15');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15000 });
			await expect(page.getByText('Contrôle géométrie')).toBeVisible({ timeout: 10000 });

			// Create second evaluation: "QCM algèbre"
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			await selectClassAndSubject(page);
			await page.locator('#ev-title').fill('QCM algèbre');
			await page.locator('#ev-date').fill('2026-06-20');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15000 });
			await expect(page.getByText('QCM algèbre')).toBeVisible({ timeout: 10000 });

			// Both evaluations should be visible
			await expect(page.getByText('Contrôle géométrie')).toBeVisible();
			await expect(page.getByText('QCM algèbre')).toBeVisible();

			// Search for "géométrie"
			const searchInput = page.getByRole('searchbox', { name: /rechercher par titre/i });
			await searchInput.fill('géométrie');

			// Wait for debounced search to trigger and results to update
			await expect(page.getByText('Contrôle géométrie')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('QCM algèbre')).not.toBeVisible({ timeout: 10000 });

			// Clear search and verify both reappear
			await page.getByRole('button', { name: /effacer la recherche/i }).click();
			await expect(page.getByText('Contrôle géométrie')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('QCM algèbre')).toBeVisible({ timeout: 10000 });
		});
	});

	// ============================================================================
	// T2: Filter evaluations by class (P2)
	// ============================================================================
	test.describe('Filter by class', () => {
		test('class filter dropdown filters the evaluation list', async ({ page }) => {
			// Seed a second class and assignment for this test
			const { schoolId, academicYearId } = resolveDeterministicIds(TENANT_ID);
			try {
				runSql(
					`INSERT INTO school_classes (id, tenant_id, school_id, academic_year_id, name, level, status, created_at, updated_at) ` +
						`VALUES (gen_random_uuid(), '${TENANT_ID}', '${schoolId}', '${academicYearId}', 'E2E-EVAL-5B', '5ème', 'active', NOW(), NOW()) ON CONFLICT DO NOTHING`
				);
				runSql(
					`INSERT INTO teacher_assignments (id, tenant_id, teacher_id, school_class_id, subject_id, academic_year_id, status, start_date, created_at, updated_at) ` +
						`SELECT gen_random_uuid(), '${TENANT_ID}', u.id, c.id, s.id, '${academicYearId}', 'active', NOW(), NOW(), NOW() ` +
						`FROM users u CROSS JOIN school_classes c CROSS JOIN subjects s ` +
						`WHERE u.email = '${TEACHER_EMAIL}' AND u.tenant_id = '${TENANT_ID}' ` +
						`AND c.name = 'E2E-EVAL-5B' AND c.tenant_id = '${TENANT_ID}' ` +
						`AND s.tenant_id = '${TENANT_ID}' ` +
						`ON CONFLICT DO NOTHING`
				);
			} catch {
				// May already exist
			}
			clearCache();

			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Create evaluation in first class (E2E-EVAL-6A)
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			const classSelect = page.locator('#ev-class');
			await expect(classSelect).toBeVisible();
			await classSelect.selectOption({ label: 'E2E-EVAL-6A' });
			const subjectSelect = page.locator('#ev-subject');
			await expect(subjectSelect).toBeEnabled({ timeout: 5000 });
			await expect(subjectSelect.locator('option')).not.toHaveCount(1, { timeout: 10000 });
			await subjectSelect.selectOption({ index: 1 });
			await page.locator('#ev-title').fill('Eval classe 6A');
			await page.locator('#ev-date').fill('2026-06-15');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15000 });
			await expect(page.getByText('Eval classe 6A')).toBeVisible({ timeout: 10000 });

			// Create evaluation in second class (E2E-EVAL-5B)
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10000 });
			const classSelect2 = page.locator('#ev-class');
			await classSelect2.selectOption({ label: 'E2E-EVAL-5B' });
			const subjectSelect2 = page.locator('#ev-subject');
			await expect(subjectSelect2).toBeEnabled({ timeout: 5000 });
			await expect(subjectSelect2.locator('option')).not.toHaveCount(1, { timeout: 10000 });
			await subjectSelect2.selectOption({ index: 1 });
			await page.locator('#ev-title').fill('Eval classe 5B');
			await page.locator('#ev-date').fill('2026-06-20');
			await page.getByRole('button', { name: 'Créer', exact: true }).click();
			await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15000 });
			await expect(page.getByText('Eval classe 5B')).toBeVisible({ timeout: 10000 });

			// Both evaluations visible initially
			await expect(page.getByText('Eval classe 6A')).toBeVisible();
			await expect(page.getByText('Eval classe 5B')).toBeVisible();

			// Filter by E2E-EVAL-6A
			const filterSelect = page.getByRole('combobox', { name: /filtrer par classe/i });
			await expect(filterSelect).toBeVisible();
			await filterSelect.selectOption({ label: 'E2E-EVAL-6A' });

			// Wait for filtered results
			await expect(page.getByText('Eval classe 6A')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('Eval classe 5B')).not.toBeVisible({ timeout: 10000 });

			// Reset filter to "Toutes les classes"
			await filterSelect.selectOption({ label: 'Toutes les classes' });

			// Both should reappear
			await expect(page.getByText('Eval classe 6A')).toBeVisible({ timeout: 10000 });
			await expect(page.getByText('Eval classe 5B')).toBeVisible({ timeout: 10000 });

			// Cleanup: remove the second class data
			try {
				runSql(`DELETE FROM grade_events WHERE grade_id IN (SELECT g.id FROM grades g JOIN evaluations e ON g.evaluation_id = e.id WHERE e.teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}') AND e.class_id IN (SELECT id FROM school_classes WHERE name = 'E2E-EVAL-5B' AND tenant_id = '${TENANT_ID}'))`);
				runSql(`DELETE FROM grades WHERE evaluation_id IN (SELECT id FROM evaluations WHERE teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}') AND class_id IN (SELECT id FROM school_classes WHERE name = 'E2E-EVAL-5B' AND tenant_id = '${TENANT_ID}'))`);
				runSql(`DELETE FROM evaluations WHERE teacher_id IN (SELECT id FROM users WHERE email = '${TEACHER_EMAIL}' AND tenant_id = '${TENANT_ID}') AND class_id IN (SELECT id FROM school_classes WHERE name = 'E2E-EVAL-5B' AND tenant_id = '${TENANT_ID}')`);
				runSql(`DELETE FROM teacher_assignments WHERE school_class_id IN (SELECT id FROM school_classes WHERE name = 'E2E-EVAL-5B' AND tenant_id = '${TENANT_ID}')`);
				runSql(`DELETE FROM school_classes WHERE name = 'E2E-EVAL-5B' AND tenant_id = '${TENANT_ID}'`);
			} catch {
				// Cleanup is best-effort
			}
		});
	});

	// ============================================================================
	// T3: Grade scale equivalence preview (P2)
	// ============================================================================
	test.describe('Grade scale preview', () => {
		test('shows equivalence preview when barème is not 20', async ({ page }) => {
			await loginAsTeacher(page);
			await navigateToEvaluations(page);

			// Open create modal
			await page.getByRole('button', { name: /nouvelle évaluation/i }).click();
			const dialog = page.getByRole('dialog');
			await expect(dialog).toBeVisible({ timeout: 10000 });

			// Default barème is 20 - no preview should appear
			const scaleInput = dialog.locator('#ev-scale');
			await expect(scaleInput).toHaveValue('20');
			const previewHint = dialog.locator('#ev-scale ~ .form-hint');
			await expect(previewHint).not.toBeVisible();

			// Change barème to 10
			await scaleInput.fill('10');

			// Verify equivalence preview appears: (10/10 = 20.0/20)
			await expect(previewHint).toBeVisible({ timeout: 5000 });
			await expect(previewHint).toHaveText('(10/10 = 20.0/20)');

			// Change barème to 5 -> (10/5 = 40.0/20)
			await scaleInput.fill('5');
			await expect(previewHint).toHaveText('(10/5 = 40.0/20)');

			// Change back to 20 -> preview should disappear
			await scaleInput.fill('20');
			await expect(previewHint).not.toBeVisible({ timeout: 5000 });
		});
	});
});
