import { hasFocusVisible } from "../../fixtures/accessibility";
import { SELECTORS } from "../../fixtures/selectors";
import { expect, test } from "../../fixtures/test";

test.describe("Keyboard Navigation @smoke", () => {
	test.beforeEach(async ({ gotoApp, waitForAppReady }) => {
		await gotoApp();
		await waitForAppReady();
	});

	test("skip link is first focusable element", async ({ page }) => {
		// Press Tab to focus skip link
		await page.keyboard.press("Tab");

		// Skip link should be focused
		const skipLink = page.locator(SELECTORS.skipLink);
		await expect(skipLink).toBeFocused();

		// Skip link should be visible when focused
		const isVisible = await skipLink.isVisible();
		expect(isVisible).toBe(true);
	});

	test("skip link navigates to main content", async ({ page }) => {
		// Focus and activate skip link
		await page.keyboard.press("Tab");
		await page.keyboard.press("Enter");

		// Main content should be focused
		const mainContent = page.locator("#main-content");
		await expect(mainContent).toBeFocused();
	});

	test("header controls are keyboard accessible @smoke", async ({ page }) => {
		// Tab through header controls
		await page.keyboard.press("Tab"); // Skip link
		await page.keyboard.press("Tab"); // Logo
		await page.keyboard.press("Tab"); // Language select

		const languageSelect = page.locator(SELECTORS.header.languageSelect);
		await expect(languageSelect).toBeFocused();

		await page.keyboard.press("Tab"); // Theme menu button

		const themeButton = page.locator(SELECTORS.header.themeMenuButton);
		await expect(themeButton).toBeFocused();
	});

	test("theme menu is keyboard operable", async ({ page }) => {
		// Navigate to theme button
		await page.keyboard.press("Tab"); // Skip link
		await page.keyboard.press("Tab"); // Logo
		await page.keyboard.press("Tab"); // Language select
		await page.keyboard.press("Tab"); // Theme button

		// Open theme menu with Enter
		await page.keyboard.press("Enter");

		// Menu should be visible
		const menu = page.locator(SELECTORS.themeMenu.root);
		await expect(menu).toBeVisible();

		// Menu items should be focusable
		const menuItems = menu.locator('[role="menuitem"]');
		const count = await menuItems.count();
		expect(count).toBeGreaterThan(0);

		// Close menu with Escape
		await page.keyboard.press("Escape");
		await expect(menu).not.toBeVisible();
	});

	test("hero read button is keyboard accessible @smoke", async ({
		page,
		waitForHero,
	}) => {
		const hero = await waitForHero();

		// Navigate to hero read button
		// Skip header controls first
		for (let i = 0; i < 4; i++) {
			await page.keyboard.press("Tab");
		}

		// Hero read button should be focusable
		const readButton = hero.locator(SELECTORS.hero.readButton);

		// Check if button is in tab order by trying to focus it
		let found = false;
		for (let i = 0; i < 10; i++) {
			const activeElement = await page.evaluate(
				() =>
					document.activeElement?.textContent?.trim() ||
					document.activeElement?.getAttribute("aria-label"),
			);

			if (activeElement?.includes("Read TL;DR")) {
				found = true;
				break;
			}

			await page.keyboard.press("Tab");
		}

		expect(found).toBe(true);
	});

	test("feed articles are keyboard navigable", async ({
		page,
		waitForFeed,
	}) => {
		const feed = await waitForFeed();

		// Get first article
		const firstArticle = feed.locator(SELECTORS.feed.articles).first();

		// Source link should be keyboard accessible
		const sourceLink = firstArticle.locator(SELECTORS.feed.articleSource);
		const hasSourceLink = (await sourceLink.count()) > 0;

		if (hasSourceLink) {
			// Tab to source link
			let attempts = 0;
			let sourceLinkFocused = false;

			while (attempts < 20 && !sourceLinkFocused) {
				await page.keyboard.press("Tab");
				const href = await page.evaluate(() =>
					document.activeElement?.getAttribute("href"),
				);

				if (href && href.startsWith("http")) {
					sourceLinkFocused = true;
				}

				attempts++;
			}

			expect(sourceLinkFocused).toBe(true);
		}

		// Read button should be keyboard accessible
		const readButton = firstArticle.locator(SELECTORS.feed.articleReadButton);

		let attempts = 0;
		let readButtonFocused = false;

		while (attempts < 30 && !readButtonFocused) {
			await page.keyboard.press("Tab");
			const text = await page.evaluate(() =>
				document.activeElement?.textContent?.trim(),
			);

			if (text === "Read TL;DR") {
				readButtonFocused = true;
			}

			attempts++;
		}

		expect(readButtonFocused).toBe(true);
	});

	test("focus-visible is shown on interactive elements", async ({
		page,
		waitForHero,
	}) => {
		const hero = await waitForHero();

		// Navigate to hero read button
		for (let i = 0; i < 4; i++) {
			await page.keyboard.press("Tab");
		}

		// Find focused element
		const focusedElement = page.locator(":focus");

		// Check that focused element has visible focus indicator
		const hasVisibleFocus = await hasFocusVisible(page, focusedElement);
		expect(hasVisibleFocus).toBe(true);
	});

	test("footer links are keyboard accessible @smoke", async ({ page }) => {
		// Navigate to footer
		const footer = page.locator(SELECTORS.footer.root);
		await footer.scrollIntoViewIfNeeded();

		// Tab through footer links
		let foundFooterLink = false;
		let attempts = 0;

		while (attempts < 50 && !foundFooterLink) {
			await page.keyboard.press("Tab");

			const activeElement = await page.evaluate(() => document.activeElement);

			// Check if we're in footer
			const isInFooter = await page.evaluate(() => {
				const active = document.activeElement;
				const footer = document.querySelector("footer");
				return footer?.contains(active);
			});

			if (isInFooter) {
				foundFooterLink = true;
			}

			attempts++;
		}

		expect(foundFooterLink).toBe(true);
	});
});

test.describe("Focus Management", () => {
	test.beforeEach(async ({ gotoApp, waitForAppReady }) => {
		await gotoApp();
		await waitForAppReady();
	});

	test("focus moves to modal when opened @smoke", async ({
		page,
		waitForHero,
	}) => {
		const hero = await waitForHero();

		// Click read button
		await hero.locator(SELECTORS.hero.readButton).click();

		// Modal should be visible
		const modal = page.locator(SELECTORS.summaryModal.root);
		await expect(modal).toBeVisible();

		// Focus should be inside modal
		const isFocusInModal = await page.evaluate(() => {
			const modal = document.querySelector('[role="dialog"]');
			const active = document.activeElement;
			return modal?.contains(active);
		});

		expect(isFocusInModal).toBe(true);
	});

	test("focus is trapped within modal", async ({ page, waitForHero }) => {
		const hero = await waitForHero();

		// Open modal
		await hero.locator(SELECTORS.hero.readButton).click();

		// Tab multiple times
		for (let i = 0; i < 20; i++) {
			await page.keyboard.press("Tab");

			// Check focus is still in modal
			const isInModal = await page.evaluate(() => {
				const modal = document.querySelector('[role="dialog"]');
				const active = document.activeElement;
				return modal?.contains(active);
			});

			expect(isInModal).toBe(true);
		}
	});
});
