import clsx from "clsx";
import { Check } from "lucide-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { Divider } from "~/components/Divider";
import { ModeImage } from "~/components/Image";
import { BANNED_MAPS } from "~/features/match-profile/banned-maps";
import { shortStageName, stageIds } from "~/modules/in-game-lists/stage-ids";
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
import { nullFilledArray } from "~/utils/arrays";
import { stageImageUrl } from "~/utils/urls";
import styles from "./ModeMapPoolPicker.module.css";

export function ModeMapPoolPicker({
	mode,
	amountToPick,
	pool,
	tiebreaker,
	onChange,
	modeTabs,
	onModeChange,
	disabled,
}: {
	mode: ModeShort;
	amountToPick: number;
	pool: StageId[];
	tiebreaker?: StageId;
	onChange: (stages: StageId[]) => void;
	/** When provided, the divider becomes a tab switcher between these modes. */
	modeTabs?: ModeShort[];
	onModeChange?: (mode: ModeShort) => void;
	/** When true, stages can't be picked or removed (view-only). */
	disabled?: boolean;
}) {
	const [wigglingStageId, setWigglingStageId] = React.useState<StageId | null>(
		null,
	);

	React.useEffect(() => {
		if (wigglingStageId === null) return;
		const timeout = setTimeout(() => {
			setWigglingStageId(null);
		}, 1000);

		return () => {
			clearTimeout(timeout);
		};
	}, [wigglingStageId]);

	const stages: (StageId | null)[] = [
		...pool,
		...nullFilledArray(amountToPick - pool.length),
	];

	const handlePickedStageClick = (stageId: StageId) => {
		onChange(pool.filter((s) => s !== stageId));
	};

	const handleUnpickedStageClick = (stageId: StageId) => {
		// is there space left?
		if (stages[amountToPick - 1] !== null) {
			setWigglingStageId(stageId);
			return;
		}

		// was it already picked?
		if (pool.includes(stageId)) {
			return;
		}

		onChange([...pool, stageId].sort((a, b) => a - b));
	};

	return (
		<div className={clsx(styles.container, "stack sm")}>
			<div className="stack sm horizontal justify-center">
				{nullFilledArray(amountToPick).map((_, index) => {
					return (
						<MapSlot
							key={index}
							number={index + 1}
							picked={stages[index] !== null}
						/>
					);
				})}
			</div>
			<Divider className={styles.divider}>
				{modeTabs && onModeChange ? (
					<div className={styles.modeTabs}>
						{modeTabs.map((tabMode) => {
							const active = tabMode === mode;

							return (
								<button
									key={tabMode}
									type="button"
									className={clsx(styles.modeTab, {
										[styles.modeTabActive]: active,
									})}
									onClick={() => onModeChange(tabMode)}
									aria-pressed={active}
									data-testid={`map-pool-mode-tab-${tabMode}`}
								>
									<ModeImage mode={tabMode} size={24} />
								</button>
							);
						})}
					</div>
				) : (
					<ModeImage mode={mode} size={32} />
				)}
			</Divider>
			<div className="stack sm horizontal flex-wrap justify-center mt-1">
				{stageIds.map((stageId) => {
					const isTiebreaker = tiebreaker === stageId;
					const banned = BANNED_MAPS[mode].includes(stageId);
					const selected = stages.includes(stageId);

					const onClick = () => {
						if (disabled) return;
						if (isTiebreaker) return;
						if (banned) return;
						if (selected) return handlePickedStageClick(stageId);

						handleUnpickedStageClick(stageId);
					};

					return (
						<MapButton
							key={stageId}
							stageId={stageId}
							onClick={onClick}
							selected={selected}
							banned={banned}
							tiebreaker={isTiebreaker}
							wiggle={wigglingStageId === stageId}
							disabled={disabled}
							testId={`map-pool-${mode}-${stageId}`}
						/>
					);
				})}
			</div>
		</div>
	);
}

function MapSlot({ number, picked }: { number: number; picked: boolean }) {
	return (
		<div
			className={clsx(styles.slot, {
				[styles.slotPicked]: picked,
			})}
		>
			{picked ? <Check className={styles.slotIcon} /> : number}
		</div>
	);
}

function MapButton({
	stageId,
	onClick,
	selected,
	banned,
	tiebreaker,
	wiggle,
	disabled,
	testId,
}: {
	stageId: StageId;
	onClick: () => void;
	selected?: boolean;
	banned?: boolean;
	tiebreaker?: boolean;
	wiggle?: boolean;
	disabled?: boolean;
	testId: string;
}) {
	const { t } = useTranslation(["game-misc"]);

	return (
		<div
			className={clsx("stack items-center relative", styles.mapButtonContainer)}
		>
			<button
				className={clsx(styles.mapButton, {
					[styles.mapButtonWiggle]: wiggle,
					[styles.mapButtonGreyedOut]: selected || banned || tiebreaker,
				})}
				style={{ "--map-image-url": `url("${stageImageUrl(stageId)}.avif")` }}
				onClick={onClick}
				disabled={disabled || banned}
				type="button"
				data-testid={testId}
			/>
			{selected ? (
				<Check className={styles.mapButtonIcon} onClick={onClick} />
			) : null}
			{tiebreaker ? (
				<div className={styles.mapButtonText}>Tiebreak</div>
			) : banned ? (
				<div className={clsx(styles.mapButtonText, "text-error")}>Banned</div>
			) : null}
			<div className={styles.mapButtonLabel}>
				{shortStageName(t(`game-misc:STAGE_${stageId}`))}
			</div>
		</div>
	);
}
