import {
	type ConditionEntry,
	type ConditionId,
	getConditionDescription,
	getConditionsForEdition,
	type PersistentDamageEntry,
	type PersistentDamageType,
} from "@initiative/domain";
import { Check, Flame, Minus, Plus } from "lucide-react";
import React, { useLayoutEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useRulesEditionContext } from "../contexts/rules-edition-context.js";
import { useClickOutside } from "../hooks/use-click-outside.js";
import { cn } from "../lib/utils";
import {
	CONDITION_COLOR_CLASSES,
	CONDITION_ICON_MAP,
} from "./condition-styles.js";
import { PersistentDamagePicker } from "./persistent-damage-picker.js";
import { Tooltip } from "./ui/tooltip.js";

interface ConditionPickerProps {
	anchorRef: React.RefObject<HTMLElement | null>;
	activeConditions: readonly ConditionEntry[] | undefined;
	activePersistentDamage?: readonly PersistentDamageEntry[];
	onToggle: (conditionId: ConditionId) => void;
	onSetValue: (conditionId: ConditionId, value: number) => void;
	onAddPersistentDamage?: (
		damageType: PersistentDamageType,
		formula: string,
	) => void;
	onClose: () => void;
}

export function ConditionPicker({
	anchorRef,
	activeConditions,
	activePersistentDamage,
	onToggle,
	onSetValue,
	onAddPersistentDamage,
	onClose,
}: Readonly<ConditionPickerProps>) {
	const ref = useRef<HTMLDivElement>(null);
	const [pos, setPos] = useState<{
		top: number;
		left: number;
		maxHeight: number;
	} | null>(null);

	const [editing, setEditing] = useState<{
		id: ConditionId;
		value: number;
	} | null>(null);
	const [showPersistentDamage, setShowPersistentDamage] = useState(false);

	useLayoutEffect(() => {
		const anchor = anchorRef.current;
		const el = ref.current;
		if (!anchor || !el) return;

		const anchorRect = anchor.getBoundingClientRect();
		const menuHeight = el.scrollHeight;
		const pad = 8;

		const spaceBelow = window.innerHeight - anchorRect.bottom - pad;
		const spaceAbove = anchorRect.top - pad;
		const openBelow = spaceBelow >= menuHeight || spaceBelow >= spaceAbove;

		const top = openBelow
			? anchorRect.bottom + 4
			: Math.max(pad, anchorRect.top - Math.min(menuHeight, spaceAbove) - 4);
		const maxHeight = openBelow ? spaceBelow : Math.min(menuHeight, spaceAbove);

		setPos({ top, left: anchorRect.left, maxHeight });
	}, [anchorRef]);

	useClickOutside(ref, onClose);

	const { edition } = useRulesEditionContext();
	const conditions = getConditionsForEdition(edition);
	const activeMap = new Map(
		(activeConditions ?? []).map((e) => [e.id, e.value]),
	);
	const showPersistentDamageEntry =
		edition === "pf2e" && !!onAddPersistentDamage;
	const persistentDamageInsertIndex = showPersistentDamageEntry
		? conditions.findIndex(
				(d) => d.label.localeCompare("Persistent Damage") > 0,
			)
		: -1;

	const persistentDamageEntry = showPersistentDamageEntry ? (
		<React.Fragment key="persistent-damage">
			<div
				className={cn(
					"flex w-full items-center gap-2 rounded px-2 py-1 text-sm transition-colors",
					showPersistentDamage && "bg-card/50",
				)}
			>
				<button
					type="button"
					className="flex flex-1 items-center gap-2"
					onClick={() => setShowPersistentDamage((prev) => !prev)}
				>
					<Flame
						size={14}
						className={
							showPersistentDamage ? "text-orange-400" : "text-muted-foreground"
						}
					/>
					<span
						className={
							showPersistentDamage ? "text-foreground" : "text-muted-foreground"
						}
					>
						Persistent Damage
					</span>
				</button>
			</div>
			{!!showPersistentDamage && (
				<PersistentDamagePicker
					activeEntries={activePersistentDamage}
					onAdd={onAddPersistentDamage}
					onClose={() => setShowPersistentDamage(false)}
				/>
			)}
		</React.Fragment>
	) : null;

	return createPortal(
		<div
			ref={ref}
			className="card-glow fixed z-50 w-fit overflow-y-auto rounded-lg border border-border bg-background p-1"
			style={
				pos
					? { top: pos.top, left: pos.left, maxHeight: pos.maxHeight }
					: { visibility: "hidden" as const }
			}
		>
			{conditions.map((def, index) => {
				const Icon = CONDITION_ICON_MAP[def.iconName];
				if (!Icon) return null;
				const isActive = activeMap.has(def.id);
				const activeValue = activeMap.get(def.id);
				const isEditing = editing?.id === def.id;
				const colorClass =
					CONDITION_COLOR_CLASSES[def.color] ?? "text-muted-foreground";

				const handleClick = () => {
					if (def.valued && edition === "pf2e") {
						const current = activeMap.get(def.id);
						setEditing({
							id: def.id,
							value: current ?? 1,
						});
					} else {
						onToggle(def.id);
					}
				};

				return (
					<React.Fragment key={def.id}>
						{index === persistentDamageInsertIndex && persistentDamageEntry}
						<Tooltip
							content={getConditionDescription(def, edition)}
							className="block"
						>
							<div
								className={cn(
									"flex w-full items-center gap-2 rounded px-2 py-1 text-sm transition-colors",
									(isActive || isEditing) && "bg-card/50",
								)}
							>
								<button
									type="button"
									className="flex flex-1 items-center gap-2"
									onClick={handleClick}
								>
									<Icon
										size={14}
										className={
											isActive || isEditing
												? colorClass
												: "text-muted-foreground"
										}
									/>
									<span
										className={
											isActive || isEditing
												? "text-foreground"
												: "text-muted-foreground"
										}
									>
										{def.label}
									</span>
								</button>
								{isActive && def.valued && edition === "pf2e" && !isEditing && (
									<span className="min-w-5 rounded-full bg-accent px-1.5 py-0.5 text-center font-medium text-primary-foreground text-xs">
										{activeValue}
									</span>
								)}
								{isEditing && (
									<div className="flex items-center gap-0.5">
										<button
											type="button"
											className="rounded p-0.5 text-foreground hover:bg-accent/40"
											onMouseDown={(e) => e.preventDefault()}
											onClick={(e) => {
												e.stopPropagation();
												if (editing.value > 1) {
													setEditing({
														...editing,
														value: editing.value - 1,
													});
												}
											}}
										>
											<Minus className="h-3 w-3" />
										</button>
										<span className="min-w-5 rounded-full bg-accent px-1.5 py-0.5 text-center font-medium text-primary-foreground text-xs">
											{editing.value}
										</span>
										{(() => {
											const atMax =
												def.maxValue !== undefined &&
												editing.value >= def.maxValue;
											return (
												<button
													type="button"
													className={cn(
														"rounded p-0.5",
														atMax
															? "cursor-not-allowed text-muted-foreground opacity-50"
															: "text-foreground hover:bg-accent/40",
													)}
													disabled={atMax}
													onMouseDown={(e) => e.preventDefault()}
													onClick={(e) => {
														e.stopPropagation();
														if (!atMax) {
															setEditing({
																...editing,
																value: editing.value + 1,
															});
														}
													}}
												>
													<Plus className="h-3 w-3" />
												</button>
											);
										})()}
										<button
											type="button"
											className="ml-0.5 rounded p-0.5 text-foreground hover:bg-accent/40"
											onMouseDown={(e) => e.preventDefault()}
											onClick={(e) => {
												e.stopPropagation();
												onSetValue(editing.id, editing.value);
												setEditing(null);
											}}
										>
											<Check className="h-3.5 w-3.5" />
										</button>
									</div>
								)}
							</div>
						</Tooltip>
					</React.Fragment>
				);
			})}
			{persistentDamageInsertIndex === -1 && persistentDamageEntry}
		</div>,
		document.body,
	);
}
