"use client";

import { AnimatePresence, motion } from "framer-motion";
import { X } from "lucide-react";
import {
	createContext,
	type ReactNode,
	useContext,
	useEffect,
	useState,
} from "react";
import { cn } from "~/lib/utils";

// Context
interface ExpandableScreenContextValue {
	isExpanded: boolean;
	expand: () => void;
	collapse: () => void;
	layoutId: string;
	triggerRadius: string;
	contentRadius: string;
	animationDuration: number;
}

const ExpandableScreenContext =
	createContext<ExpandableScreenContextValue | null>(null);

function useExpandableScreen() {
	const context = useContext(ExpandableScreenContext);
	if (!context) {
		throw new Error(
			"useExpandableScreen must be used within an ExpandableScreen",
		);
	}
	return context;
}

// Root Component
interface ExpandableScreenProps {
	children: ReactNode;
	defaultExpanded?: boolean;
	onExpandChange?: (expanded: boolean) => void;
	layoutId?: string;
	triggerRadius?: string;
	contentRadius?: string;
	animationDuration?: number;
	lockScroll?: boolean;
}

/**
 * @link https://www.cult-ui.com/docs/components/expandable-screen
 *  */
export function ExpandableScreen({
	children,
	defaultExpanded = false,
	onExpandChange,
	layoutId = "expandable-card",
	triggerRadius = "100px",
	contentRadius = "24px",
	animationDuration = 0.3,
	lockScroll = true,
}: ExpandableScreenProps) {
	const [isExpanded, setIsExpanded] = useState(defaultExpanded);

	const expand = () => {
		setIsExpanded(true);
		onExpandChange?.(true);
	};

	const collapse = () => {
		setIsExpanded(false);
		onExpandChange?.(false);
	};

	useEffect(() => {
		if (lockScroll) {
			if (isExpanded) {
				document.body.style.overflow = "hidden";
			} else {
				document.body.style.overflow = "unset";
			}
		}
	}, [isExpanded, lockScroll]);

	return (
		<ExpandableScreenContext.Provider
			value={{
				isExpanded,
				expand,
				collapse,
				layoutId,
				triggerRadius,
				contentRadius,
				animationDuration,
			}}
		>
			{children}
		</ExpandableScreenContext.Provider>
	);
}

// Trigger Component
interface ExpandableScreenTriggerProps {
	children: ReactNode;
	className?: string;
}

export function ExpandableScreenTrigger({
	children,
	className = "",
}: ExpandableScreenTriggerProps) {
	const { isExpanded, expand, layoutId, triggerRadius } = useExpandableScreen();

	return (
		<AnimatePresence initial={false}>
			{!isExpanded && (
				<motion.div className={`relative inline-block ${className}`}>
					{/* Background layer with shared layoutId for morphing */}
					<motion.div
						className="absolute inset-0 transform-gpu will-change-transform"
						layout
						layoutId={layoutId}
						style={{
							borderRadius: triggerRadius,
						}}
					/>
					{/* Content layer that fades out on expand */}
					<motion.div
						animate={{ opacity: 1, scale: 1 }}
						className="relative cursor-pointer"
						exit={{ opacity: 0, scale: 0.8 }}
						initial={{ opacity: 0, scale: 0.8 }}
						layout={false}
						onClick={expand}
						transition={{ delay: 0.2 }}
					>
						{children}
					</motion.div>
				</motion.div>
			)}
		</AnimatePresence>
	);
}

// Content Component
interface ExpandableScreenContentProps {
	children: ReactNode;
	className?: string;
	showCloseButton?: boolean;
	closeButtonClassName?: string;
}

export function ExpandableScreenContent({
	children,
	className = "",
	showCloseButton = true,
	closeButtonClassName = "",
}: ExpandableScreenContentProps) {
	const { isExpanded, collapse, layoutId, contentRadius, animationDuration } =
		useExpandableScreen();

	return (
		<AnimatePresence initial={false}>
			{isExpanded && (
				<div className="fixed inset-0 z-50 flex items-center justify-center p-3 sm:p-2">
					{/* Morphing background with shared layoutId */}
					<motion.div
						className={`relative flex h-full w-full transform-gpu overflow-y-auto will-change-transform ${className}`}
						layout
						layoutId={layoutId}
						style={{
							borderRadius: contentRadius,
						}}
						transition={{ duration: animationDuration }}
					>
						<motion.div
							animate={{ opacity: 1 }}
							className="relative z-20 w-full"
							initial={{ opacity: 0 }}
							transition={{ delay: 0.15, duration: 0.4 }}
						>
							{children}
						</motion.div>

						{showCloseButton && (
							<motion.button
								aria-label="Close"
								className={cn(
									"absolute top-6 right-6 z-30 flex h-10 w-10 cursor-pointer items-center justify-center rounded-full transition-colors",
									"bg-transparent text-white hover:bg-white/10 dark:text-primary-foreground hover:dark:bg-primary-foreground/10",
									closeButtonClassName,
								)}
								onClick={collapse}
							>
								<X className="h-5 w-5" />
							</motion.button>
						)}
					</motion.div>
				</div>
			)}
		</AnimatePresence>
	);
}

// Background Component (optional)
interface ExpandableScreenBackgroundProps {
	trigger?: ReactNode;
	content?: ReactNode;
	className?: string;
}

export function ExpandableScreenBackground({
	trigger,
	content,
	className = "",
}: ExpandableScreenBackgroundProps) {
	const { isExpanded } = useExpandableScreen();

	if (isExpanded && content) {
		return <div className={className}>{content}</div>;
	}

	if (!isExpanded && trigger) {
		return <div className={className}>{trigger}</div>;
	}

	return null;
}

export { useExpandableScreen };
