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

// Extract port from PLAYWRIGHT_BASE_URL or use default (4173 matches playwright.config.ts)
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}`;

// Test credentials per role
const ADMIN_EMAIL = 'e2e-rbac-admin@example.com';
const ADMIN_PASSWORD = 'RbacAdmin123';
const TEACHER_EMAIL = 'e2e-rbac-teacher@example.com';
const TEACHER_PASSWORD = 'RbacTeacher123';
const PARENT_EMAIL = 'e2e-rbac-parent@example.com';
const PARENT_PASSWORD = 'RbacParent123';

test.describe('Role-Based Access Control [P0]', () => {
	test.describe.configure({ mode: 'serial' });

	test.beforeAll(async () => {
		const projectRoot = join(__dirname, '../..');
		const composeFile = join(projectRoot, 'compose.yaml');

		// Create admin user
		execSync(
			`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${ADMIN_EMAIL} --password=${ADMIN_PASSWORD} --role=ROLE_ADMIN 2>&1`,
			{ encoding: 'utf-8' }
		);

		// Create teacher user
		execSync(
			`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${TEACHER_EMAIL} --password=${TEACHER_PASSWORD} --role=ROLE_PROF 2>&1`,
			{ encoding: 'utf-8' }
		);

		// Create parent user
		execSync(
			`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${PARENT_EMAIL} --password=${PARENT_PASSWORD} --role=ROLE_PARENT 2>&1`,
			{ encoding: 'utf-8' }
		);
	});

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

	// ============================================================================
	// Admin access - should have access to all /admin pages
	// ============================================================================
	test.describe('Admin Access', () => {
		test('[P0] admin user can access /admin/users page', async ({ page }) => {
			await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/users`);

			// Admin should see the users management page
			await expect(page).toHaveURL(/\/admin\/users/);
			await expect(
				page.locator('.users-table, .empty-state')
			).toBeVisible({ timeout: 10000 });
		});

		test('[P0] admin user can access /admin/classes page', async ({ page }) => {
			await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/classes`);

			await expect(page).toHaveURL(/\/admin\/classes/);
			await expect(
				page.getByRole('heading', { name: /gestion des classes/i })
			).toBeVisible({ timeout: 10000 });
		});

		test('[P0] admin user can access /admin/pedagogy page', async ({ page }) => {
			await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/pedagogy`);

			await expect(page).toHaveURL(/\/admin\/pedagogy/);
		});

		test('[P0] admin user can access /admin page', async ({ page }) => {
			await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin`);

			// /admin redirects to /admin/users
			await expect(page).toHaveURL(/\/admin\/users/);
			await expect(
				page.getByRole('heading', { name: /gestion des utilisateurs/i })
			).toBeVisible({ timeout: 10000 });
		});
	});

	// ============================================================================
	// Teacher access - CAN access /admin layout (for image-rights, pedagogy)
	// but backend protects sensitive pages (users, classes, etc.) with 403
	// ============================================================================
	test.describe('Teacher Access Restrictions', () => {
		test('[P0] teacher can access /admin layout', async ({ page }) => {
			await loginAs(page, TEACHER_EMAIL, TEACHER_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/image-rights`);

			// Teacher can access admin layout for authorized pages
			await page.waitForURL(/\/admin\/image-rights/, { timeout: 30000 });
			expect(page.url()).toContain('/admin/image-rights');
		});
	});

	// ============================================================================
	// Parent access - should NOT have access to /admin pages
	// ============================================================================
	test.describe('Parent Access Restrictions', () => {
		test('[P0] parent cannot access /admin/users page', async ({ page }) => {
			await loginAs(page, PARENT_EMAIL, PARENT_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/users`);

			// Admin guard redirects non-admin users to /dashboard
			await page.waitForURL(/\/dashboard/, { timeout: 30000 });
			expect(page.url()).toContain('/dashboard');
		});

		test('[P0] parent cannot access /admin/classes page', async ({ page }) => {
			await loginAs(page, PARENT_EMAIL, PARENT_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin/classes`);

			// Admin guard redirects non-admin users to /dashboard
			await page.waitForURL(/\/dashboard/, { timeout: 30000 });
			expect(page.url()).toContain('/dashboard');
		});

		test('[P0] parent cannot access /admin page', async ({ page }) => {
			await loginAs(page, PARENT_EMAIL, PARENT_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin`);

			// Admin guard redirects non-admin users to /dashboard
			await page.waitForURL(/\/dashboard/, { timeout: 30000 });
			expect(page.url()).toContain('/dashboard');
		});
	});

	// ============================================================================
	// Unauthenticated user - should be redirected to /login
	// ============================================================================
	test.describe('Unauthenticated Access', () => {
		test('[P0] unauthenticated user is redirected from /settings/sessions to /login', async ({ page }) => {
			// Clear any existing session
			await page.context().clearCookies();

			await page.goto(`${ALPHA_URL}/settings/sessions`);

			// Should be redirected to login
			await expect(page).toHaveURL(/\/login/, { timeout: 10000 });
		});

		test('[P0] unauthenticated user is redirected from /admin/users to /login', async ({ page }) => {
			await page.context().clearCookies();

			await page.goto(`${ALPHA_URL}/admin/users`);

			// Should be redirected away from /admin/users (to /login or /dashboard)
			await page.waitForURL((url) => !url.toString().includes('/admin/users'), { timeout: 10000 });
			expect(page.url()).not.toContain('/admin/users');
		});
	});

	// ============================================================================
	// Navigation reflects role permissions
	// ============================================================================
	test.describe('Navigation Reflects Permissions', () => {
		test('[P0] admin layout shows admin navigation links', async ({ page }) => {
			await loginAs(page, ADMIN_EMAIL, ADMIN_PASSWORD);
			await page.goto(`${ALPHA_URL}/admin`);

			// Admin layout should show grouped navigation (category triggers in desktop nav)
			const nav = page.locator('.desktop-nav');
			await expect(nav.getByRole('button', { name: /personnes/i })).toBeVisible({ timeout: 15000 });
			await expect(nav.getByRole('button', { name: /organisation/i })).toBeVisible();

			// Hover to reveal dropdown links
			await nav.getByRole('button', { name: /personnes/i }).hover();
			await expect(nav.getByRole('menuitem', { name: 'Utilisateurs' })).toBeVisible();
		});

		test('[P0] teacher sees dashboard without admin navigation', async ({ page }) => {
			await loginAs(page, TEACHER_EMAIL, TEACHER_PASSWORD);

			// Teacher should be on dashboard
			await expect(page).toHaveURL(/\/dashboard/);

			// Teacher should not see admin-specific navigation in the dashboard layout
			// The dashboard header should not have admin links like "Utilisateurs"
			const adminUsersLink = page.locator('.desktop-nav').getByRole('link', { name: 'Utilisateurs' });
			await expect(adminUsersLink).not.toBeVisible();
		});
	});
});
