import type { CreatureId } from "@initiative/domain";
import { PanelRightClose, Pin, PinOff } from "lucide-react";
import type { ReactNode } from "react";
import { useEffect, useState } from "react";
import { useBestiaryContext } from "../contexts/bestiary-context.js";
import { useSidePanelContext } from "../contexts/side-panel-context.js";
import { useSwipeToDismiss } from "../hooks/use-swipe-to-dismiss.js";
import { cn } from "../lib/utils.js";
import { BulkImportPrompt } from "./bulk-import-prompt.js";
import { SourceFetchPrompt } from "./source-fetch-prompt.js";
import { SourceManager } from "./source-manager.js";
import { StatBlock } from "./stat-block.js";
import { Button } from "./ui/button.js";

interface StatBlockPanelProps {
	panelRole: "browse" | "pinned";
	side: "left" | "right";
}

function extractSourceCode(cId: CreatureId): string {
	const colonIndex = cId.indexOf(":");
	if (colonIndex === -1) return "";
	return cId.slice(0, colonIndex).toUpperCase();
}

function CollapsedTab({
	creatureName,
	side,
	onToggleCollapse,
}: Readonly<{
	creatureName: string;
	side: "left" | "right";
	onToggleCollapse: () => void;
}>) {
	return (
		<button
			type="button"
			onClick={onToggleCollapse}
			className={cn(
				"flex h-full w-[40px] cursor-pointer items-center justify-center text-muted-foreground hover:text-hover-neutral",
				side === "right" ? "self-start" : "self-end",
			)}
			aria-label="Expand stat block panel"
		>
			<span className="writing-vertical-rl font-medium text-sm">
				{creatureName}
			</span>
		</button>
	);
}

function PanelHeader({
	panelRole,
	showPinButton,
	onToggleCollapse,
	onPin,
	onUnpin,
}: Readonly<{
	panelRole: "browse" | "pinned";
	showPinButton: boolean;
	onToggleCollapse: () => void;
	onPin: () => void;
	onUnpin: () => void;
}>) {
	return (
		<div className="flex items-center justify-between border-border border-b px-4 py-2">
			<div className="flex items-center gap-1">
				{panelRole === "browse" && (
					<Button
						variant="ghost"
						size="icon-sm"
						onClick={onToggleCollapse}
						className="text-muted-foreground"
						aria-label="Collapse stat block panel"
					>
						<PanelRightClose className="h-4 w-4" />
					</Button>
				)}
			</div>
			<div className="flex items-center gap-1">
				{panelRole === "browse" && showPinButton && (
					<Button
						variant="ghost"
						size="icon-sm"
						onClick={onPin}
						className="text-muted-foreground"
						aria-label="Pin creature"
					>
						<Pin className="h-4 w-4" />
					</Button>
				)}
				{panelRole === "pinned" && (
					<Button
						variant="ghost"
						size="icon-sm"
						onClick={onUnpin}
						className="text-muted-foreground"
						aria-label="Unpin creature"
					>
						<PinOff className="h-4 w-4" />
					</Button>
				)}
			</div>
		</div>
	);
}

function DesktopPanel({
	isCollapsed,
	side,
	creatureName,
	panelRole,
	showPinButton,
	onToggleCollapse,
	onPin,
	onUnpin,
	children,
}: Readonly<{
	isCollapsed: boolean;
	side: "left" | "right";
	creatureName: string;
	panelRole: "browse" | "pinned";
	showPinButton: boolean;
	onToggleCollapse: () => void;
	onPin: () => void;
	onUnpin: () => void;
	children: ReactNode;
}>) {
	const sideClasses = side === "left" ? "left-0 border-r" : "right-0 border-l";
	const collapsedTranslate =
		side === "right"
			? "translate-x-[calc(100%-40px)]"
			: "translate-x-[calc(-100%+40px)]";

	return (
		<div
			className={cn(
				"panel-glow fixed top-0 bottom-0 flex w-[400px] flex-col border-border bg-card transition-slide-panel",
				sideClasses,
				isCollapsed ? collapsedTranslate : "translate-x-0",
			)}
		>
			{isCollapsed ? (
				<CollapsedTab
					creatureName={creatureName}
					side={side}
					onToggleCollapse={onToggleCollapse}
				/>
			) : (
				<>
					<PanelHeader
						panelRole={panelRole}
						showPinButton={showPinButton}
						onToggleCollapse={onToggleCollapse}
						onPin={onPin}
						onUnpin={onUnpin}
					/>
					<div className="flex-1 overflow-y-auto p-4">{children}</div>
				</>
			)}
		</div>
	);
}

function MobileDrawer({
	onDismiss,
	children,
}: Readonly<{
	onDismiss: () => void;
	children: ReactNode;
}>) {
	const { offsetX, isSwiping, handlers } = useSwipeToDismiss(onDismiss);

	return (
		<div className="fixed inset-0 z-50">
			<button
				type="button"
				className="fade-in absolute inset-0 animate-in bg-black/50"
				onClick={onDismiss}
				aria-label="Close stat block"
			/>
			<div
				className={cn(
					"panel-glow absolute top-0 right-0 bottom-0 w-[85%] max-w-md border-border border-l bg-card",
					!isSwiping && "animate-slide-in-right",
				)}
				style={
					isSwiping ? { transform: `translateX(${offsetX}px)` } : undefined
				}
				{...handlers}
			>
				<div className="flex items-center justify-between border-border border-b px-4 py-2">
					<Button
						variant="ghost"
						size="icon-sm"
						onClick={onDismiss}
						className="text-muted-foreground"
						aria-label="Collapse stat block panel"
					>
						<PanelRightClose className="h-4 w-4" />
					</Button>
				</div>
				<div className="h-[calc(100%-41px)] overflow-y-auto p-4">
					{children}
				</div>
			</div>
		</div>
	);
}

function usePanelRole(panelRole: "browse" | "pinned") {
	const sidePanel = useSidePanelContext();
	const { getCreature } = useBestiaryContext();

	const creatureId =
		panelRole === "browse"
			? sidePanel.selectedCreatureId
			: sidePanel.pinnedCreatureId;
	const creature = creatureId ? (getCreature(creatureId) ?? null) : null;

	const isBrowse = panelRole === "browse";
	return {
		creatureId,
		creature,
		isCollapsed: isBrowse ? sidePanel.isRightPanelCollapsed : false,
		onToggleCollapse: isBrowse ? sidePanel.toggleCollapse : () => {},
		onDismiss: isBrowse ? sidePanel.dismissPanel : () => {},
		onPin: isBrowse ? sidePanel.togglePin : () => {},
		onUnpin: panelRole === "pinned" ? sidePanel.unpin : () => {},
		showPinButton: isBrowse && sidePanel.isWideDesktop && !!creature,
		bulkImportMode: isBrowse && sidePanel.bulkImportMode,
		sourceManagerMode: isBrowse && sidePanel.sourceManagerMode,
	};
}

export function StatBlockPanel({
	panelRole,
	side,
}: Readonly<StatBlockPanelProps>) {
	const { isSourceCached } = useBestiaryContext();
	const {
		creatureId,
		creature,
		isCollapsed,
		onToggleCollapse,
		onDismiss,
		onPin,
		onUnpin,
		showPinButton,
		bulkImportMode,
		sourceManagerMode,
	} = usePanelRole(panelRole);

	const [isDesktop, setIsDesktop] = useState(
		() => globalThis.matchMedia("(min-width: 1024px)").matches,
	);
	const [needsFetch, setNeedsFetch] = useState(false);
	const [checkingCache, setCheckingCache] = useState(false);

	useEffect(() => {
		const mq = globalThis.matchMedia("(min-width: 1024px)");
		const handler = (e: MediaQueryListEvent) => setIsDesktop(e.matches);
		mq.addEventListener("change", handler);
		return () => mq.removeEventListener("change", handler);
	}, []);

	useEffect(() => {
		if (!creatureId || creature) {
			setNeedsFetch(false);
			return;
		}

		const sourceCode = extractSourceCode(creatureId);
		if (!sourceCode) {
			setNeedsFetch(false);
			return;
		}

		setCheckingCache(true);
		void isSourceCached(sourceCode).then((cached) => {
			setNeedsFetch(!cached);
			setCheckingCache(false);
		});
	}, [creatureId, creature, isSourceCached]);

	if (!creatureId && !bulkImportMode && !sourceManagerMode) return null;

	const sourceCode = creatureId ? extractSourceCode(creatureId) : "";

	const handleSourceLoaded = () => {
		setNeedsFetch(false);
	};

	const renderContent = () => {
		if (sourceManagerMode) {
			return <SourceManager />;
		}

		if (bulkImportMode) {
			return <BulkImportPrompt />;
		}

		if (checkingCache) {
			return (
				<div className="p-4 text-muted-foreground text-sm">Loading...</div>
			);
		}

		if (creature) {
			return <StatBlock creature={creature} />;
		}

		if (needsFetch && sourceCode) {
			return (
				<SourceFetchPrompt
					sourceCode={sourceCode}
					onSourceLoaded={handleSourceLoaded}
				/>
			);
		}

		return (
			<div className="p-4 text-muted-foreground text-sm">
				No stat block available
			</div>
		);
	};

	let fallbackName = "Creature";
	if (sourceManagerMode) fallbackName = "Sources";
	else if (bulkImportMode) fallbackName = "Import All Sources";
	const creatureName = creature?.name ?? fallbackName;

	if (isDesktop) {
		return (
			<DesktopPanel
				isCollapsed={isCollapsed}
				side={side}
				creatureName={creatureName}
				panelRole={panelRole}
				showPinButton={showPinButton}
				onToggleCollapse={onToggleCollapse}
				onPin={onPin}
				onUnpin={onUnpin}
			>
				{renderContent()}
			</DesktopPanel>
		);
	}

	if (panelRole === "pinned" || isCollapsed) return null;

	return <MobileDrawer onDismiss={onDismiss}>{renderContent()}</MobileDrawer>;
}
