import { GripVertical } from "lucide-react";
import type React from "react";
import { createContext, useContext } from "react";
import { useComparisonSlider } from "@/hooks/use-comparison-slider";
import { cn } from "@/lib/utils";

/**
 * Comparison Slider component for comparing two views side by side
 *
 * @example
 * ```tsx
 * <ComparisonSlider>
 *   <ComparisonSlider.First>
 *     <img src="/original.jpg" alt="Original" />
 *   </ComparisonSlider.First>
 *   <ComparisonSlider.Second>
 *     <img src="/translated.jpg" alt="Translated" />
 *   </ComparisonSlider.Second>
 * </ComparisonSlider>
 * ```
 */

interface ComparisonSliderContextValue {
	position: number;
	setPosition: React.Dispatch<React.SetStateAction<number>>;
	containerRef: React.RefObject<HTMLDivElement>;
}

const ComparisonSliderContext =
	createContext<ComparisonSliderContextValue | null>(null);

interface ComparisonSliderProps {
	/**
	 * Initial position of the slider (0-100)
	 */
	defaultPosition?: number;
	/**
	 * CSS class for the container
	 */
	className?: string;
	/**
	 * Class for the divider/handle
	 */
	handleClassName?: string;
	/**
	 * Whether to maintain aspect ratio
	 */
	aspectRatio?: string | boolean;
	/**
	 * Direction of the comparison (horizontal or vertical)
	 */
	direction?: "horizontal" | "vertical";
	/**
	 * Children components
	 */
	children?: React.ReactNode;
}

const ComparisonSlider = ({
	defaultPosition = 50,
	className,
	handleClassName,
	aspectRatio,
	direction = "horizontal",
	children,
}: ComparisonSliderProps) => {
	const {
		position,
		setPosition,
		containerRef,
		isDragging,
		handleMouseDown,
		handleTouchStart,
	} = useComparisonSlider(defaultPosition, direction);
	const isHorizontal = direction === "horizontal";
	let aspectRatioStyle = {};
	if (aspectRatio) {
		if (typeof aspectRatio === "boolean" && aspectRatio) {
			aspectRatioStyle = { aspectRatio: "16/9" };
		} else if (typeof aspectRatio === "string") {
			aspectRatioStyle = { aspectRatio };
		}
	}
	return (
		<ComparisonSliderContext.Provider
			value={{ position, setPosition, containerRef }}
		>
			<div
				ref={containerRef}
				className={cn(
					"relative overflow-hidden",
					isHorizontal ? "w-full" : "h-full",
					className,
				)}
				style={aspectRatioStyle}
			>
				{children}
				{/* Handle/Divider */}
				<button
					type="button"
					aria-label="Move comparison slider"
					tabIndex={0}
					className={cn(
						"absolute z-10",
						isHorizontal
							? "top-0 bottom-0 w-1 cursor-ew-resize"
							: "left-0 right-0 h-1 cursor-ns-resize",
						isDragging && "select-none",
						handleClassName,
					)}
					style={{
						[isHorizontal ? "left" : "top"]: `${position}%`,
						transform: isHorizontal ? "translateX(-50%)" : "translateY(-50%)",
						backgroundColor: "hsl(var(--primary) / 0.2)",
					}}
					onMouseDown={handleMouseDown}
					onTouchStart={handleTouchStart}
				>
					<div
						className={cn(
							"absolute flex items-center justify-center rounded-full shadow bg-background border border-border",
							isHorizontal
								? "top-1/2 -translate-y-1/2 h-8 w-8"
								: "left-1/2 -translate-x-1/2 h-8 w-8",
						)}
						style={{
							[isHorizontal ? "left" : "top"]: "50%",
							transform: isHorizontal ? "translateX(-50%)" : "translateY(-50%)",
						}}
					>
						<GripVertical
							className={cn(
								"h-4 w-4 text-muted-foreground",
								isHorizontal ? "" : "rotate-90",
							)}
						/>
					</div>
				</button>
			</div>
		</ComparisonSliderContext.Provider>
	);
};

interface SliderItemProps {
	/**
	 * Children components
	 */
	children: React.ReactNode;
	/**
	 * CSS class for the component
	 */
	className?: string;
}

const First = ({ children, className }: SliderItemProps) => {
	const context = useContext(ComparisonSliderContext);
	if (!context)
		throw new Error(
			"ComparisonSlider.First must be used within ComparisonSlider",
		);
	const { position } = context;
	return (
		<div
			className={cn("absolute inset-0 overflow-hidden", className)}
			style={{ clipPath: `inset(0 ${100 - position}% 0 0)` }}
		>
			{children}
		</div>
	);
};

const Second = ({ children, className }: SliderItemProps) => {
	const context = useContext(ComparisonSliderContext);
	if (!context)
		throw new Error(
			"ComparisonSlider.Second must be used within ComparisonSlider",
		);
	return <div className={cn("absolute inset-0", className)}>{children}</div>;
};

ComparisonSlider.First = First;
ComparisonSlider.Second = Second;

export { ComparisonSlider };
