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 — unique to this spec to avoid cross-spec collisions
const ADMIN_EMAIL = 'e2e-imgrights-admin@example.com';
const ADMIN_PASSWORD = 'ImgRightsAdmin123';
const STUDENT_EMAIL = 'e2e-imgrights-student@example.com';
const STUDENT_PASSWORD = 'ImgRightsStudent123';

let _studentUserId: string;

/**
 * Extracts the User ID from the Symfony console table output.
 *
 * The create-test-user command outputs a table like:
 *   | Property | Value                                |
 *   | User ID  | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
 */
function extractUserId(output: string): string {
	const match = output.match(/User ID\s+([a-f0-9-]{36})/i);
	if (!match) {
		throw new Error(`Could not extract User ID from command output:\n${output}`);
	}
	return match[1];
}

test.describe('Image Rights Management', () => {
	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 student user and capture userId
		const studentOutput = execSync(
			`docker compose -f "${composeFile}" exec -T php php bin/console app:dev:create-test-user --tenant=ecole-alpha --email=${STUDENT_EMAIL} --password=${STUDENT_PASSWORD} --role=ROLE_ELEVE 2>&1`,
			{ encoding: 'utf-8' }
		);
		_studentUserId = extractUserId(studentOutput);

		try {
			execSync(
				`docker compose -f "${composeFile}" exec -T php php bin/console cache:pool:clear paginated_queries.cache 2>&1`,
				{ encoding: 'utf-8' }
			);
		} catch {
			// Cache pool may not exist in all environments
		}
	});

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

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

	/**
	 * Waits for the image rights page to finish loading.
	 *
	 * After hydration, the page either shows the student tables (sections with
	 * h2 headings) or the empty state. Waiting for one of these ensures the
	 * component is interactive and API data has been fetched.
	 */
	async function waitForPageLoaded(page: import('@playwright/test').Page) {
		await expect(
			page.getByRole('heading', { name: /droit à l'image/i })
		).toBeVisible({ timeout: 15000 });

		// Wait for either the stats bar (data loaded) or empty state (no students)
		await expect(
			page.locator('.stats-bar')
				.or(page.locator('.empty-state'))
		).toBeVisible({ timeout: 15000 });
	}

	// ============================================================================
	// [P1] Page loads with correct structure
	// ============================================================================
	test('[P1] page loads with correct structure', async ({ page }) => {
		await loginAsAdmin(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);
		await waitForPageLoaded(page);

		// Title
		await expect(
			page.getByRole('heading', { name: /droit à l'image/i })
		).toBeVisible();

		// Subtitle
		await expect(
			page.getByText(/consultez et gérez les autorisations/i)
		).toBeVisible();

		// Status filter dropdown
		const filterSelect = page.locator('#filter-status');
		await expect(filterSelect).toBeVisible();

		// Verify filter options
		const options = filterSelect.locator('option');
		await expect(options.filter({ hasText: /tous les statuts/i })).toHaveCount(1);
		await expect(options.filter({ hasText: /^Autorisé$/ })).toHaveCount(1);
		await expect(options.filter({ hasText: /^Refusé$/ })).toHaveCount(1);
		await expect(options.filter({ hasText: /^Non renseigné$/ })).toHaveCount(1);

		// Search input
		await expect(
			page.locator('input[type="search"]')
		).toBeVisible();

		// Export CSV button
		await expect(
			page.getByRole('button', { name: /exporter csv/i })
		).toBeVisible();

		// Filter and reset buttons
		await expect(
			page.getByRole('button', { name: /^filtrer$/i })
		).toBeVisible();
		await expect(
			page.getByRole('button', { name: /réinitialiser/i })
		).toBeVisible();

		// At least one student section should be visible (pagination may hide the other on page 1)
		await expect(
			page.getByRole('heading', { name: /élèves autorisés/i })
				.or(page.getByRole('heading', { name: /élèves non autorisés/i }))
				.first()
		).toBeVisible();

		// Stats bar
		await expect(page.locator('.stats-bar')).toBeVisible();
	});

	// ============================================================================
	// [P1] Filter by status works
	// ============================================================================
	test('[P1] filter by status works', async ({ page }) => {
		await loginAsAdmin(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);
		await waitForPageLoaded(page);

		// Select "Autorisé" in the status filter
		await page.locator('#filter-status').selectOption('authorized');

		// Click "Filtrer" to apply
		await page.getByRole('button', { name: /^filtrer$/i }).click();

		// Wait for the page to reload with filtered data
		await expect(page).toHaveURL(/status=authorized/);
		await waitForPageLoaded(page);

		// After filtering by "Autorisé", either:
		// - The stats bar shows with 0 unauthorized, OR
		// - The empty state shows (no authorized students found)
		const statsBarVisible = await page.locator('.stats-bar').isVisible();
		if (statsBarVisible) {
			const dangerCount = await page.locator('.stat-count.stat-danger').count();
			if (dangerCount > 0) {
				const unauthorizedCount = await page.locator('.stat-count.stat-danger').textContent();
				expect(parseInt(unauthorizedCount ?? '0', 10)).toBe(0);
			}
			// No stat-danger element means no unauthorized students — correct after filtering by "Autorisé"
		} else {
			await expect(page.locator('.empty-state')).toBeVisible();
		}

		// Reset filters to restore original state
		await page.getByRole('button', { name: 'Réinitialiser', exact: true }).click();
		await waitForPageLoaded(page);

		// URL should no longer contain status filter
		expect(page.url()).not.toContain('status=');
	});

	// ============================================================================
	// [P1] Status update via dropdown
	// ============================================================================
	test('[P1] status update via dropdown', async ({ page }) => {
		await loginAsAdmin(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);
		await waitForPageLoaded(page);

		// Find the first student's action select (in either authorized or unauthorized table)
		const firstActionSelect = page.locator('td[data-label="Actions"] select').first();
		await expect(firstActionSelect).toBeVisible({ timeout: 10000 });

		// Get the current value
		const currentValue = await firstActionSelect.inputValue();

		// Pick a different status to switch to
		const newValue = currentValue === 'authorized' ? 'refused' : 'authorized';

		// Change the status
		await firstActionSelect.selectOption(newValue);

		// Success message should appear
		await expect(
			page.locator('.alert-success')
		).toBeVisible({ timeout: 10000 });
		await expect(
			page.locator('.alert-success')
		).toContainText(/statut mis à jour/i);

		// Restore original status to leave test data clean
		// Need to re-locate because the student may have moved to a different section
		const restoredSelect = page.locator('td[data-label="Actions"] select').first();
		await restoredSelect.selectOption(currentValue);
		await expect(
			page.locator('.alert-success')
		).toBeVisible({ timeout: 10000 });
	});

	// ============================================================================
	// [P1] Export CSV button triggers download
	// ============================================================================
	test('[P1] export CSV button triggers download', async ({ page }) => {
		await loginAsAdmin(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);
		await waitForPageLoaded(page);

		// Listen for download event
		const downloadPromise = page.waitForEvent('download', { timeout: 15000 });

		// Click the export button
		await page.getByRole('button', { name: /exporter csv/i }).click();

		// Verify the download starts
		const download = await downloadPromise;
		expect(download.suggestedFilename()).toBe('droits-image.csv');

		// Success message should appear
		await expect(
			page.locator('.alert-success')
		).toBeVisible({ timeout: 10000 });
		await expect(
			page.locator('.alert-success')
		).toContainText(/export csv/i);
	});

	// ============================================================================
	// [P2] Text search filters students
	// ============================================================================
	test('[P2] text search filters students', async ({ page }) => {
		await loginAsAdmin(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);
		await waitForPageLoaded(page);

		// Get the total student count before searching
		const totalBefore = await page.locator('.stat-count.stat-total').textContent();
		const totalBeforeNum = parseInt(totalBefore ?? '0', 10);

		// Type a search term that matches the test student email prefix
		const searchInput = page.locator('input[type="search"]');
		await searchInput.fill('e2e-imgrights');

		// Wait for the debounced search to apply (300ms debounce + some margin)
		await page.waitForTimeout(500);

		// The URL should be updated with the search parameter
		await expect(page).toHaveURL(/search=e2e-imgrights/);

		// The filtered count should be less than or equal to the total
		// and specifically should find our test student
		const totalAfter = await page.locator('.stat-count.stat-total').textContent();
		const totalAfterNum = parseInt(totalAfter ?? '0', 10);
		expect(totalAfterNum).toBeGreaterThanOrEqual(1);
		expect(totalAfterNum).toBeLessThanOrEqual(totalBeforeNum);

		// Clear the search
		await searchInput.clear();
		await page.waitForTimeout(500);

		// Total should be restored
		expect(page.url()).not.toContain('search=');
	});

	// ============================================================================
	// [P2] Unauthorized role redirected
	// ============================================================================
	test('[P2] student role cannot access image rights page', async ({ page }) => {
		await loginAsStudent(page);
		await page.goto(`${ALPHA_URL}/admin/image-rights`);

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