import { expect, test, type Page } from '@playwright/test';
import { loginAsAdmin, logout } from '../fixtures/auth';

// Phase B1 — Auth & Navigation. Every interaction with the login form
// and the layout-level redirects, plus the obvious adversarial inputs.

const VALID_USERNAME = process.env.E2E_ADMIN_USERNAME ?? 'admin';
const VALID_PASSWORD = process.env.E2E_ADMIN_PASSWORD ?? 'admin';

function failOnDialog(page: Page): void {
	page.on('dialog', async (dialog) => {
		await dialog.dismiss();
		throw new Error(`Unexpected browser dialog fired: ${dialog.type()} — "${dialog.message()}"`);
	});
}

test.describe('B1 auth — unauthenticated', () => {
	test.use({ storageState: { cookies: [], origins: [] } });

	test('valid credentials land on the apps list', async ({ page }) => {
		await loginAsAdmin(page);
		await expect(page.getByRole('heading', { name: 'Apps', level: 1 })).toBeVisible();
	});

	test('wrong password shows an inline error and stays on /login', async ({ page }) => {
		await page.goto('/admin/login');
		await page.getByLabel('Username').fill(VALID_USERNAME);
		await page.getByLabel('Password').fill('definitely-not-the-password');
		await page.getByRole('button', { name: /sign in/i }).click();

		const error = page.locator('.error');
		await expect(error).toBeVisible();
		await expect(error).not.toHaveText('');
		await expect(page).toHaveURL(/\/admin\/login$/);
		// localStorage must remain empty — a failed login should not
		// leak a session token.
		const token = await page.evaluate(() => localStorage.getItem('picloud.admin.token'));
		expect(token).toBeNull();
	});

	test('empty submit is blocked by the browser and does not navigate', async ({ page }) => {
		await page.goto('/admin/login');
		await page.getByRole('button', { name: /sign in/i }).click();
		// HTML5 validation prevents submission; URL is unchanged and the
		// username input is reported invalid.
		await expect(page).toHaveURL(/\/admin\/login$/);
		const usernameInvalid = await page
			.getByLabel('Username')
			.evaluate((el: HTMLInputElement) => !el.validity.valid);
		expect(usernameInvalid).toBe(true);
		await expect(page.locator('.error')).toBeHidden();
	});

	test('visiting an authed route redirects to /login', async ({ page }) => {
		await page.goto('/admin/apps');
		await expect(page).toHaveURL(/\/admin\/login$/);
		await expect(page.getByLabel('Username')).toBeVisible();
	});

	test('password field is type=password (no plaintext echo)', async ({ page }) => {
		await page.goto('/admin/login');
		await expect(page.getByLabel('Password')).toHaveAttribute('type', 'password');
	});

	test('xss payload in username is escaped and does not execute', async ({ page }) => {
		failOnDialog(page);
		const payload = '<script>window.__xss = true;</script><img src=x onerror=alert(1)>';

		await page.goto('/admin/login');
		await page.getByLabel('Username').fill(payload);
		await page.getByLabel('Password').fill('whatever');
		await page.getByRole('button', { name: /sign in/i }).click();

		// Whatever the API does with that input, the page must remain
		// safe: no script tag injected into the DOM, no global side
		// effect, and a visible error (since the credentials don't
		// match any user).
		await expect(page.locator('.error')).toBeVisible();
		const xssRan = await page.evaluate(
			() => (window as unknown as { __xss?: boolean }).__xss === true
		);
		expect(xssRan).toBe(false);
		const injectedScript = await page.locator('script:has-text("__xss")').count();
		expect(injectedScript).toBe(0);
		// The form must still be functional after the rejected attempt.
		await page.getByLabel('Username').fill('');
		await page.getByLabel('Username').fill(VALID_USERNAME);
		await page.getByLabel('Password').fill('');
		await page.getByLabel('Password').fill(VALID_PASSWORD);
		await page.getByRole('button', { name: /sign in/i }).click();
		await expect(page).toHaveURL(/\/admin\/apps$/);
	});
});

test.describe('B1 auth — authenticated', () => {
	test('visiting /login while signed in bounces to /apps', async ({ page }) => {
		await page.goto('/admin/login');
		await expect(page).toHaveURL(/\/admin\/apps$/);
	});
});

test.describe('B1 auth — logout', () => {
	// Logout must NOT use the shared storageState token, or it would
	// invalidate the session every other test relies on. Each run
	// here logs in fresh so its session is disposable.
	test.use({ storageState: { cookies: [], origins: [] } });

	test('logout clears the session and lands on /login', async ({ page }) => {
		await loginAsAdmin(page);
		await expect(page.getByRole('heading', { name: 'Apps', level: 1 })).toBeVisible();
		await logout(page);
		const token = await page.evaluate(() => localStorage.getItem('picloud.admin.token'));
		expect(token).toBeNull();
		// And the authed area is now gated again.
		await page.goto('/admin/apps');
		await expect(page).toHaveURL(/\/admin\/login$/);
	});
});
