import { useCallback, useEffect, useRef, useState } from "react";
import { MODE_CONFIG, type Mode } from "../../../src/actors/arena/config.ts";
import type { ArenaMatchmakerConn } from "../../actor-types.ts";
import type { GameClient } from "../../client.ts";
import { ArenaBot } from "./bot.ts";
import { waitForAssignment } from "./wait-for-assignment.ts";

export interface ArenaMatchInfo {
	matchId: string;
	playerId: string;
	teamId: number;
	mode: Mode;
}

const MODES: Array<{ id: Mode; label: string }> = [
	{ id: "1v1", label: "1v1" },
	{ id: "ffa", label: "FFA" },
	{ id: "duo", label: "Duo" },
	{ id: "squad", label: "Squad" },
];

export function ArenaMenu({
	client,
	onReady,
	onBack,
}: {
	client: GameClient;
	onReady: (info: ArenaMatchInfo) => void;
	onBack: () => void;
}) {
	const [mode, setMode] = useState<Mode>("ffa");
	const [status, setStatus] = useState<
		"idle" | "queuing" | "queued" | "matched" | "error"
	>("idle");
	const [queueCount, setQueueCount] = useState(0);
	const [error, setError] = useState("");

	const mmRef = useRef<ArenaMatchmakerConn | null>(null);
	const abortRef = useRef(false);
	const botsRef = useRef<ArenaBot[]>([]);
	const matchedRef = useRef(false);

	const capacity = MODE_CONFIG[mode].capacity;

	const cleanup = useCallback((destroyBots = true) => {
		abortRef.current = true;
		if (destroyBots) {
			for (const bot of botsRef.current) bot.destroy();
			botsRef.current = [];
		}
		const mm = mmRef.current;
		mmRef.current = null;
		mm?.dispose();
	}, []);

	const leaveQueue = useCallback(async () => {
		await cleanup();
		setQueueCount(0);
		setStatus("idle");
	}, [cleanup]);

	const queueForMatch = async () => {
		setStatus("queuing");
		setError("");
		abortRef.current = false;
		matchedRef.current = false;
		try {
			const mm = client.arenaMatchmaker.getOrCreate(["main"]).connect();
			mmRef.current = mm;

			let myPlayerId: string | null = null;
			let matched = false;

			const resolveMatch = (assignment: ArenaMatchInfo) => {
				if (matched || abortRef.current) return;
				matched = true;
				matchedRef.current = true;
				setStatus("matched");
				setTimeout(async () => {
					// Don't destroy bots - they need to connect to the match.
					await cleanup(false);
					onReady(assignment);
				}, 1500);
			};

			mm.on("queueUpdate", (data) => {
				setQueueCount(data.counts[mode] ?? 0);
			});

			setStatus("queued");

			const response = await mm.queueForMatch({
				mode,
			});
			if (!response?.playerId || abortRef.current)
				throw new Error("Failed to queue");
			myPlayerId = response.playerId;

			const sizes = await mm.getQueueSizes();
			if (!abortRef.current) setQueueCount(sizes[mode] ?? 0);

			const assignment = await waitForAssignment<ArenaMatchInfo>(
				mm,
				myPlayerId,
			);
			resolveMatch(assignment);
		} catch (err) {
			if (abortRef.current) return;
			await cleanup();
			setError(err instanceof Error ? err.message : String(err));
			setStatus("error");
		}
	};

	const addBot = () => {
		const bot = new ArenaBot(client, mode);
		botsRef.current.push(bot);
	};

	useEffect(() => {
		return () => {
			// Don't destroy bots if we're transitioning to the game view.
			cleanup(!matchedRef.current);
		};
	}, [cleanup]);

	const isQueued = status === "queued" || status === "matched";

	return (
		<div className="app">
			<button
				className="back-link"
				onClick={isQueued ? () => void leaveQueue() : onBack}
			>
				&larr; {isQueued ? "Leave Queue" : "Back"}
			</button>
			<div className="menu-container">
				<h2>Arena</h2>
				<p className="menu-description">
					Mode-based fixed-capacity matches with hitscan combat. Use
					WASD to move, click to shoot. First to 10 kills wins.
				</p>

				{status === "idle" || status === "error" ? (
					<>
						<div className="mode-selector">
							{MODES.map((m) => (
								<button
									key={m.id}
									className={`btn ${mode === m.id ? "btn-primary" : "btn-secondary"}`}
									onClick={() => setMode(m.id)}
								>
									{m.label}
								</button>
							))}
						</div>
						<button
							className="btn btn-primary"
							onClick={() => void queueForMatch()}
							style={{ marginTop: 12 }}
						>
							Queue
						</button>
						{status === "error" && (
							<div className="status-box">
								<p className="status-error">{error}</p>
							</div>
						)}
					</>
				) : status === "queuing" ? (
					<div className="queue-status">
						<p className="queue-label">Joining queue...</p>
					</div>
				) : status === "queued" ? (
					<div className="queue-status">
						<div className="queue-mode-badge">
							{mode.toUpperCase()}
						</div>
						<div className="queue-count">
							{queueCount}
							<span className="queue-count-sep">/</span>
							{capacity}
						</div>
						<div className="queue-label">players in queue</div>
						<div className="queue-bar">
							<div
								className="queue-bar-fill"
								style={{
									width: `${(queueCount / capacity) * 100}%`,
								}}
							/>
						</div>
						<div
							style={{ display: "flex", gap: 12, marginTop: 20 }}
						>
							<button
								className="btn btn-secondary"
								onClick={addBot}
							>
								Add Bot
							</button>
							<button
								className="btn btn-secondary"
								onClick={() => void leaveQueue()}
							>
								Leave Queue
							</button>
						</div>
					</div>
				) : status === "matched" ? (
					<div className="queue-status">
						<div className="match-found-text">Match Found!</div>
						<p className="queue-label">Connecting to match...</p>
					</div>
				) : null}
			</div>
		</div>
	);
}
