import { test, expect } from '@playwright/test';
import { execSync } from 'child_process';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Each browser project gets its own token to avoid conflicts
let testToken: string | null = null;

// eslint-disable-next-line no-empty-pattern
test.beforeAll(async ({ }, testInfo) => {
	const browserName = testInfo.project.name;

	// Create a unique token for this browser project
	try {
		const projectRoot = join(__dirname, '../..');
		const composeFile = join(projectRoot, 'compose.yaml');
		const email = `e2e-${browserName}@example.com`;

		const result = execSync(
			`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-activation-token --email=${email} 2>&1`,
			{ encoding: 'utf-8' }
		);

		const tokenMatch = result.match(/Token\s+([a-f0-9-]{36})/i);
		if (tokenMatch) {
			testToken = tokenMatch[1];
			 
			console.warn(`[${browserName}] Test token created: ${testToken}`);
		} else {
			console.error(`[${browserName}] Could not extract token from output:`, result);
		}
	} catch (error) {
		console.error(`[${browserName}] Failed to create test token:`, error);
	}
});

function getToken(): string {
	if (!testToken) {
		throw new Error('No test token available. Make sure Docker is running.');
	}
	return testToken;
}

test.describe('Account Activation Flow', () => {
	test.describe('Token Validation', () => {
		test('displays error for invalid token', async ({ page }) => {
			await page.goto('/activate/invalid-token-uuid-format');

			// Wait for the error state
			await expect(page.getByRole('heading', { name: /lien invalide/i })).toBeVisible();
			await expect(page.getByText(/contacter votre établissement/i)).toBeVisible();
		});

		test('displays error for non-existent token', async ({ page }) => {
			// Use a valid UUID format but non-existent token
			await page.goto('/activate/00000000-0000-0000-0000-000000000000');

			// Shows error because token doesn't exist
			const heading = page.getByRole('heading', { name: /lien invalide/i });
			await expect(heading).toBeVisible();
		});
	});

	test.describe('Password Form', () => {
		test('validates password requirements in real-time', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			// Wait for form to be visible (token must be valid)
			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			const passwordInput = page.locator('#password');

			// Test minimum length requirement - should NOT be valid yet
			await passwordInput.fill('Abc1');
			const minLengthItem = page.locator('.password-requirements li').filter({ hasText: /8 caractères/ });
			await expect(minLengthItem).not.toHaveClass(/valid/);

			// Test uppercase requirement - missing
			await passwordInput.fill('abcd1234');
			const uppercaseItem = page.locator('.password-requirements li').filter({ hasText: /majuscule/ });
			await expect(uppercaseItem).not.toHaveClass(/valid/);

			// Test digit requirement - missing
			await passwordInput.fill('Abcdefgh');
			const digitItem = page.locator('.password-requirements li').filter({ hasText: /chiffre/ });
			await expect(digitItem).not.toHaveClass(/valid/);

			// Valid password (without special char) should show 4/5 checkmarks
			// Requirements: minLength, uppercase, lowercase, digit, specialChar
			// "Abcdefgh1" satisfies: minLength(9>=8), uppercase(A), lowercase(bcdefgh), digit(1)
			await passwordInput.fill('Abcdefgh1');
			const validItems = page.locator('.password-requirements li.valid');
			await expect(validItems).toHaveCount(4);
		});

		test('requires password confirmation to match', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			const passwordInput = page.locator('#password');
			const confirmInput = page.locator('#passwordConfirmation');

			await passwordInput.fill('SecurePass123!');
			await confirmInput.fill('DifferentPass123!');

			await expect(page.getByText(/mots de passe ne correspondent pas/i)).toBeVisible();

			// Fix confirmation
			await confirmInput.fill('SecurePass123!');
			await expect(page.getByText(/mots de passe ne correspondent pas/i)).not.toBeVisible();
		});

		test('submit button is disabled until form is valid', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			const submitButton = page.getByRole('button', { name: /activer mon compte/i });

			// Initially disabled
			await expect(submitButton).toBeDisabled();

			// Fill valid password (must include special char)
			await page.locator('#password').fill('SecurePass123!');
			await page.locator('#passwordConfirmation').fill('SecurePass123!');

			// Should now be enabled
			await expect(submitButton).toBeEnabled();
		});
	});

	test.describe('Establishment Info Display', () => {
		test('shows establishment name and role when token is valid', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			// School info should be visible
			await expect(page.locator('.school-info')).toBeVisible();
			await expect(page.locator('.school-name')).toBeVisible();
			await expect(page.locator('.account-type')).toBeVisible();
		});
	});

	test.describe('Password Visibility Toggle', () => {
		test('toggles password visibility', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			const passwordInput = page.locator('#password');
			const toggleButton = page.locator('.toggle-password');

			// Initially password type
			await expect(passwordInput).toHaveAttribute('type', 'password');

			// Click toggle
			await toggleButton.click();
			await expect(passwordInput).toHaveAttribute('type', 'text');

			// Click again to hide
			await toggleButton.click();
			await expect(passwordInput).toHaveAttribute('type', 'password');
		});
	});

	test.describe('Full Activation Flow', () => {
		// TODO: Investigate CI timeout issue - activation works locally but times out in CI
		// The token is created successfully but the redirect to /login?activated=true doesn't happen
		// This might be a race condition or timing issue specific to the CI environment
		test.skip(!!process.env.CI, 'Activation flow times out in CI - needs investigation');

		test('activates account and redirects to login', async ({ page }) => {
			const token = getToken();
			await page.goto(`/activate/${token}`);

			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			const submitButton = page.getByRole('button', { name: /activer mon compte/i });

			// Button should be disabled initially (no password yet)
			await expect(submitButton).toBeDisabled();

			// Fill valid password (must include special char)
			await page.locator('#password').fill('SecurePass123!');
			await page.locator('#passwordConfirmation').fill('SecurePass123!');

			// Wait for validation to complete - button should now be enabled
			await expect(submitButton).toBeEnabled({ timeout: 2000 });

			// Submit and wait for navigation
			await Promise.all([
				page.waitForURL(/\/login\?activated=true/, { timeout: 10000 }),
				submitButton.click()
			]);

			// Verify success message
			await expect(page.getByText(/compte a été activé avec succès/i)).toBeVisible();
		});
	});
});

test.describe('Login Page After Activation', () => {
	test('shows success message when redirected after activation', async ({ page }) => {
		await page.goto('/login?activated=true');

		await expect(page.getByText(/compte a été activé avec succès/i)).toBeVisible();
		await expect(page.getByRole('heading', { name: /connexion/i })).toBeVisible();
	});

	test('does not show success message without query param', async ({ page }) => {
		await page.goto('/login');

		await expect(page.getByText(/compte a été activé avec succès/i)).not.toBeVisible();
		await expect(page.getByRole('heading', { name: /connexion/i })).toBeVisible();
	});
});

test.describe('Parental Consent Flow (Minor User)', () => {
	// These tests would require seeded data for a minor user
	test.skip('shows consent required message for minor without consent', async () => {
		// Would navigate to activation page for a minor user token
		// and verify the consent required message is displayed
	});

	test.skip('allows activation after parental consent is given', async () => {
		// Would verify the full flow:
		// 1. Minor receives activation link
		// 2. Parent gives consent
		// 3. Minor can then activate their account
	});
});
