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);

/**
 * Helper to create a password reset token via CLI command.
 */
function createResetToken(options: { email: string; expired?: boolean }): string | null {
	const projectRoot = join(__dirname, '../..');
	const composeFile = join(projectRoot, 'compose.yaml');

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

		const tokenMatch = result.match(/Token\s+([a-f0-9-]{36})/i);
		if (tokenMatch) {
			return tokenMatch[1];
		}
		console.error('Could not extract reset token from output:', result);
		return null;
	} catch (error) {
		console.error('Failed to create reset token:', error);
		return null;
	}
}

/**
 * Helper to create an activation token via CLI command.
 */
function createActivationToken(options: { email: string; tenant?: string }): string | null {
	const projectRoot = join(__dirname, '../..');
	const composeFile = join(projectRoot, 'compose.yaml');
	const tenant = options.tenant ?? 'ecole-alpha';

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

		const tokenMatch = result.match(/Token\s+([a-f0-9-]{36})/i);
		if (tokenMatch) {
			return tokenMatch[1];
		}
		console.error('Could not extract activation token from output:', result);
		return null;
	} catch (error) {
		console.error('Failed to create activation token:', error);
		return null;
	}
}

test.describe('Expired/Invalid Token Scenarios [P0]', () => {
	// ============================================================================
	// Activation Token Edge Cases
	// ============================================================================
	test.describe('Activation Token Validation', () => {
		test('[P0] invalid activation token format shows error', async ({ page }) => {
			// Use a clearly invalid token format (not a UUID)
			await page.goto('/activate/invalid-token-not-a-uuid');

			// Should show an error indicating the link is invalid
			await expect(
				page.getByRole('heading', { name: /lien invalide/i })
			).toBeVisible({ timeout: 10000 });
			await expect(
				page.getByText(/contacter votre établissement/i)
			).toBeVisible();
		});

		test('[P0] non-existent activation token shows error', async ({ page }) => {
			// Use a valid UUID format but a token that does not exist
			await page.goto('/activate/00000000-0000-0000-0000-000000000000');

			// Should show error because token doesn't exist in the database
			await expect(
				page.getByRole('heading', { name: /lien invalide/i })
			).toBeVisible({ timeout: 10000 });
		});

		test('[P0] reusing an already-used activation token shows error', async ({ page }, testInfo) => {
			const email = `e2e-reuse-act-${testInfo.project.name}-${Date.now()}@example.com`;
			const token = createActivationToken({ email });
			test.skip(!token, 'Could not create test activation token');

			// First activation: use the token
			await page.goto(`/activate/${token}`);

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

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

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

			// Submit the activation
			await submitButton.click();

			// Wait for successful activation (redirects to login with query param)
			await expect(page).toHaveURL(/\/login\?activated=true/, { timeout: 10000 });

			// Second attempt: try to reuse the same token
			await page.goto(`/activate/${token}`);

			// Should show an error because the token has already been consumed
			await expect(
				page.getByRole('heading', { name: /lien invalide/i })
			).toBeVisible({ timeout: 10000 });
		});
	});

	// ============================================================================
	// Password Reset Token Edge Cases
	// ============================================================================
	test.describe('Password Reset Token Validation', () => {
		test('[P0] invalid password reset token shows error after submission', async ({ page }) => {
			// Use a valid UUID format but a token that does not exist
			await page.goto('/reset-password/00000000-0000-0000-0000-000000000000');

			// The form is shown initially (validation happens on submit)
			const form = page.locator('form');
			await expect(form).toBeVisible({ timeout: 5000 });

			// Fill valid password and submit
			await page.locator('#password').fill('ValidPassword123!');
			await page.locator('#confirmPassword').fill('ValidPassword123!');

			await page.getByRole('button', { name: /réinitialiser/i }).click();

			// Should show error after submission
			await expect(
				page.getByRole('heading', { name: 'Lien invalide' })
			).toBeVisible({ timeout: 10000 });
		});

		test('[P0] expired password reset token shows error after submission', async ({ page }, testInfo) => {
			const email = `e2e-exp-reset-${testInfo.project.name}-${Date.now()}@example.com`;
			const token = createResetToken({ email, expired: true });
			test.skip(!token, 'Could not create expired test token');

			await page.goto(`/reset-password/${token}`);

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

			// Fill valid password and submit
			await page.locator('#password').fill('ValidPassword123!');
			await page.locator('#confirmPassword').fill('ValidPassword123!');

			await page.getByRole('button', { name: /réinitialiser/i }).click();

			// Should show expired/invalid error
			await expect(
				page.getByRole('heading', { name: 'Lien invalide' })
			).toBeVisible({ timeout: 10000 });
		});

		test('[P0] reusing a password reset token shows error', async ({ page }, testInfo) => {
			const email = `e2e-reuse-reset-${testInfo.project.name}-${Date.now()}@example.com`;
			const token = createResetToken({ email });
			test.skip(!token, 'Could not create test token');

			// First reset: use the token successfully
			await page.goto(`/reset-password/${token}`);
			await expect(page.locator('form')).toBeVisible({ timeout: 5000 });

			await page.locator('#password').fill('FirstPassword123!');
			await page.locator('#confirmPassword').fill('FirstPassword123!');
			await page.getByRole('button', { name: /réinitialiser/i }).click();

			// Wait for success
			await expect(
				page.getByRole('heading', { name: 'Mot de passe modifié' })
			).toBeVisible({ timeout: 10000 });

			// Second attempt: try to reuse the same token
			await page.goto(`/reset-password/${token}`);
			await expect(page.locator('form')).toBeVisible({ timeout: 5000 });

			await page.locator('#password').fill('SecondPassword123!');
			await page.locator('#confirmPassword').fill('SecondPassword123!');
			await page.getByRole('button', { name: /réinitialiser/i }).click();

			// Should show error (token already used)
			await expect(
				page.getByRole('heading', { name: 'Lien invalide' })
			).toBeVisible({ timeout: 10000 });
		});
	});
});
