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

import type { Encounter } from "@initiative/domain";
import { combatantId } from "@initiative/domain";
import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { TurnNavigation } from "../turn-navigation";

afterEach(cleanup);

function renderNav(overrides: Partial<Encounter> = {}) {
	const encounter: Encounter = {
		combatants: [
			{ id: combatantId("1"), name: "Goblin" },
			{ id: combatantId("2"), name: "Conjurer" },
		],
		activeIndex: 0,
		roundNumber: 1,
		...overrides,
	};

	return render(
		<TurnNavigation
			encounter={encounter}
			onAdvanceTurn={vi.fn()}
			onRetreatTurn={vi.fn()}
			onClearEncounter={vi.fn()}
		/>,
	);
}

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

		it("renders the combatant name separately from the round badge", () => {
			renderNav();
			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();
			expect(container.textContent).not.toContain("—");
		});

		it("round badge and combatant name are siblings in the center area", () => {
			renderNav();
			const badge = screen.getByText("R1");
			const name = screen.getByText("Goblin");
			expect(badge.parentElement).toBe(name.parentElement);
		});

		it("updates the round badge when round changes", () => {
			const { rerender } = render(
				<TurnNavigation
					encounter={{
						combatants: [{ id: combatantId("1"), name: "Goblin" }],
						activeIndex: 0,
						roundNumber: 2,
					}}
					onAdvanceTurn={vi.fn()}
					onRetreatTurn={vi.fn()}
					onClearEncounter={vi.fn()}
				/>,
			);
			expect(screen.getByText("R2")).toBeInTheDocument();

			rerender(
				<TurnNavigation
					encounter={{
						combatants: [{ id: combatantId("1"), name: "Goblin" }],
						activeIndex: 0,
						roundNumber: 3,
					}}
					onAdvanceTurn={vi.fn()}
					onRetreatTurn={vi.fn()}
					onClearEncounter={vi.fn()}
				/>,
			);
			expect(screen.getByText("R3")).toBeInTheDocument();
			expect(screen.queryByText("R2")).not.toBeInTheDocument();
		});

		it("renders the next combatant name when turn advances", () => {
			const { rerender } = render(
				<TurnNavigation
					encounter={{
						combatants: [
							{ id: combatantId("1"), name: "Goblin" },
							{ id: combatantId("2"), name: "Conjurer" },
						],
						activeIndex: 0,
						roundNumber: 1,
					}}
					onAdvanceTurn={vi.fn()}
					onRetreatTurn={vi.fn()}
					onClearEncounter={vi.fn()}
				/>,
			);
			expect(screen.getByText("Goblin")).toBeInTheDocument();

			rerender(
				<TurnNavigation
					encounter={{
						combatants: [
							{ id: combatantId("1"), name: "Goblin" },
							{ id: combatantId("2"), name: "Conjurer" },
						],
						activeIndex: 1,
						roundNumber: 1,
					}}
					onAdvanceTurn={vi.fn()}
					onRetreatTurn={vi.fn()}
					onClearEncounter={vi.fn()}
				/>,
			);
			expect(screen.getByText("Conjurer")).toBeInTheDocument();
		});
	});

	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({
				combatants: [{ id: combatantId("1"), name: longName }],
			});
			const nameEl = screen.getByText(longName);
			expect(nameEl.className).toContain("truncate");
		});

		it("renders three-zone layout with a single-character name", () => {
			renderNav({
				combatants: [{ id: combatantId("1"), 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({
				combatants: [{ id: combatantId("1"), 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({
				combatants: [{ id: combatantId("1"), name: name40 }],
			});
			const nameEl = screen.getByText(name40);
			expect(nameEl).toBeInTheDocument();
			// The truncate class is applied but CSS only visually truncates if content overflows
			expect(nameEl.className).toContain("truncate");
		});
	});

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

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

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