// @vitest-environment jsdom
import "@testing-library/jest-dom/vitest";

import { combatantId } from "@initiative/domain";
import { cleanup, render, screen } from "@testing-library/react";
import type { ReactNode } from "react";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import { createTestAdapters } from "../../__tests__/adapters/in-memory-adapters.js";
import {
	buildCombatant,
	buildEncounter,
} from "../../__tests__/factories/index.js";
import { AllProviders } from "../../__tests__/test-providers.js";
import { TurnNavigation } from "../turn-navigation.js";

beforeAll(() => {
	Object.defineProperty(globalThis, "matchMedia", {
		writable: true,
		value: vi.fn().mockImplementation((query: string) => ({
			matches: false,
			media: query,
			onchange: null,
			addListener: vi.fn(),
			removeListener: vi.fn(),
			addEventListener: vi.fn(),
			removeEventListener: vi.fn(),
			dispatchEvent: vi.fn(),
		})),
	});
});

afterEach(cleanup);

function renderNav(encounter = buildEncounter()) {
	const adapters = createTestAdapters({ encounter });
	return render(<TurnNavigation />, {
		wrapper: ({ children }: { children: ReactNode }) => (
			<AllProviders adapters={adapters}>{children}</AllProviders>
		),
	});
}

describe("TurnNavigation", () => {
	describe("US1: Round badge and combatant name", () => {
		it("renders the round badge with correct round number", () => {
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: "Goblin" })],
					roundNumber: 3,
				}),
			);
			expect(screen.getByText("R3")).toBeInTheDocument();
		});

		it("renders the combatant name separately from the round badge", () => {
			renderNav(
				buildEncounter({
					combatants: [
						buildCombatant({ id: combatantId("c-1"), name: "Goblin" }),
						buildCombatant({ id: combatantId("c-2"), name: "Conjurer" }),
					],
					activeIndex: 0,
					roundNumber: 1,
				}),
			);
			const badge = screen.getByText("R1");
			const name = screen.getByText("Goblin");
			expect(badge).toBeInTheDocument();
			expect(name).toBeInTheDocument();
			expect(badge).not.toBe(name);
			expect(badge.closest("[class]")).not.toBe(name.closest("[class]"));
		});

		it("does not render an em dash between round and name", () => {
			const { container } = renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: "Goblin" })],
				}),
			);
			expect(container.textContent).not.toContain("\u2014");
		});

		it("round badge is in the left zone and name is in the center zone", () => {
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: "Goblin" })],
				}),
			);
			const badge = screen.getByText("R1");
			const name = screen.getByText("Goblin");
			// Badge and name are in separate grid cells to prevent layout shifts
			expect(badge.parentElement).not.toBe(name.parentElement);
		});
	});

	describe("US2: Layout robustness", () => {
		it("applies truncation styles to long combatant names", () => {
			const longName =
				"Ancient Red Dragon Wyrm of the Northern Wastes and Beyond";
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: longName })],
				}),
			);
			const nameEl = screen.getByText(longName);
			expect(nameEl.className).toContain("truncate");
		});

		it("renders three-zone layout with a single-character name", () => {
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: "O" })],
				}),
			);
			expect(screen.getByText("R1")).toBeInTheDocument();
			expect(screen.getByText("O")).toBeInTheDocument();
			expect(
				screen.getByRole("button", { name: "Previous turn" }),
			).toBeInTheDocument();
			expect(
				screen.getByRole("button", { name: "Next turn" }),
			).toBeInTheDocument();
		});

		it("keeps all action buttons accessible regardless of name length", () => {
			const longName = "A".repeat(60);
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: longName })],
				}),
			);
			expect(
				screen.getByRole("button", { name: "Previous turn" }),
			).toBeInTheDocument();
			expect(
				screen.getByRole("button", { name: "Next turn" }),
			).toBeInTheDocument();
		});

		it("renders a 40-character name without truncation class issues", () => {
			const name40 = "A".repeat(40);
			renderNav(
				buildEncounter({
					combatants: [buildCombatant({ name: name40 })],
				}),
			);
			const nameEl = screen.getByText(name40);
			expect(nameEl).toBeInTheDocument();
			expect(nameEl.className).toContain("truncate");
		});
	});

	describe("US3: No combatants state", () => {
		it("shows the round badge when there are no combatants", () => {
			renderNav(buildEncounter({ combatants: [], roundNumber: 1 }));
			expect(screen.getByText("R1")).toBeInTheDocument();
		});

		it("shows 'No combatants' placeholder text", () => {
			renderNav(buildEncounter({ combatants: [] }));
			expect(screen.getByText("No combatants")).toBeInTheDocument();
		});

		it("disables navigation buttons when there are no combatants", () => {
			renderNav(buildEncounter({ combatants: [] }));
			expect(
				screen.getByRole("button", { name: "Previous turn" }),
			).toBeDisabled();
			expect(screen.getByRole("button", { name: "Next turn" })).toBeDisabled();
		});
	});
});
