import { useFormContext, Controller } from 'react-hook-form';
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { cn } from '@/lib/utils';
import {
	Popover,
	PopoverTrigger,
	PopoverContent,
} from '@/components/ui/popover';
import {
	Command,
	CommandEmpty,
	CommandGroup,
	CommandInput,
	CommandItem,
	CommandList,
} from '@/components/ui/command';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { ChevronDown } from 'lucide-react';
import LoadingSpinner from '../loader/LoadingSpinner';

interface Options {
	value: string;
	label: string;
}

interface RHFSelectWithSearchProps {
	name: string;
	label: string;
	options: Options[];
	isRequired?: boolean;
	isLoading?: boolean;
	isFetchingMore?: boolean;
	isSearchable?: boolean;
	disabled?: boolean;
	isNullable?: boolean;
	hasMore?: boolean;
	defaultValueLabel: string;
	onSearch?: (value: string) => void;
	fetchMore?: () => void;
	className?: string;
	onChange?: (value: string | undefined) => void;
}

const RHFSelectWithSearch: React.FC<RHFSelectWithSearchProps> = ({
	name,
	label,
	options,
	isRequired = true,
	isLoading = false,
	isFetchingMore = false,
	isSearchable = false,
	disabled = false,
	isNullable = true,
	hasMore = false,
	defaultValueLabel,
	onSearch,
	fetchMore,
	className,
	onChange,
}) => {
	const { control, setValue, clearErrors } = useFormContext();
	const [searchTerm, setSearchTerm] = useState('');
	const [popoverOpen, setPopoverOpen] = useState(false);
	const inputRef = useRef<HTMLButtonElement>(null);
	const commandListRef = useRef<HTMLDivElement>(null);
	const [inputWidth, setInputWidth] = useState<number | undefined>(undefined);
	const sentinelRef = useRef<HTMLDivElement>(null);
	const observerRef = useRef<IntersectionObserver | null>(null);

	const displayedOptions = useMemo(() => {
		if (isSearchable && !onSearch && searchTerm.trim().length > 0) {
			const normalized = searchTerm.trim().toLowerCase();
			return options.filter((opt) =>
				opt.label.toLowerCase().includes(normalized)
			);
		}
		return options;
	}, [isSearchable, onSearch, searchTerm, options]);

	const handleSelect = (value: string | undefined) => {
		setValue(name, value);
		clearErrors(name);
		setPopoverOpen(false);
	};

	useEffect(() => {
		if (inputRef.current) {
			setInputWidth(inputRef.current.offsetWidth);
		}
	}, [popoverOpen]);

	useEffect(() => {
		if (!popoverOpen || !fetchMore || !hasMore || !sentinelRef.current) {
			if (observerRef.current) {
				observerRef.current.disconnect();
				observerRef.current = null;
			}
			return;
		}

		observerRef.current = new IntersectionObserver(
			(entries) => {
				const [entry] = entries;
				if (entry.isIntersecting && !isFetchingMore) {
					fetchMore?.();
				}
			},
			{
				root: commandListRef.current,
				rootMargin: '0px 0px 100px 0px',
				threshold: 0.1,
			}
		);

		observerRef.current.observe(sentinelRef.current);

		return () => {
			observerRef.current?.disconnect();
		};
	}, [popoverOpen, fetchMore, hasMore, isFetchingMore]);

	return (
		<Controller
			name={name}
			control={control}
			render={({ field, fieldState: { error } }) => (
				<div className={cn('mb-2 w-full relative', className)}>
					{label && (
						<Label className="text-sm font-medium mb-1 block">
							{label}{' '}
							{isRequired ? (
								<span className="text-red-500 align-middle">*</span>
							) : (
								<span className="text-gray-400 font-normal text-[10px]">
									(optional)
								</span>
							)}
						</Label>
					)}

					<Popover open={popoverOpen} modal onOpenChange={setPopoverOpen}>
						<PopoverTrigger asChild disabled={disabled}>
							<Button
								ref={inputRef}
								role="combobox"
								type="button"
								disabled={disabled}
								className={cn(
									' w-full h-10 text-[16px] font-normal px-4 py-2 rounded-lg border border-gray-200 placeholder:text-gray-400 focus-visible:outline-none focus-visible:ring-0 focus:border-primary hover:bg-white hover:text-primary',
									!field.value && 'text-gray-400',
									error
										? 'border-red-500 bg-[#FCE9E9]'
										: 'bg-white border border-gray-200',
									className,
									'text-black w-full flex justify-between  text-xs '
								)}
							>
								{field.value
									? options.find((opt) => opt.value === field.value)
											?.label || defaultValueLabel
									: `Select ${label}`}
								<ChevronDown className="w-5 h-5 hover:text-primary" />
							</Button>
						</PopoverTrigger>

						{error && (
							<p className="text-[#EE0004] text-[11px] mt-1">
								{error.message}
							</p>
						)}

						<PopoverContent
							className="p-0"
							style={{ width: inputWidth }}
							align="start"
							side="bottom"
							sideOffset={4}
							avoidCollisions={false}
						>
							<Command className="bg-white">
								{isSearchable && (
									<CommandInput
										placeholder={`Search ${label.toLowerCase()}...`}
										className="px-3 py-2  text-[16px]  focus:outline-none h-14 "
										value={searchTerm}
										onValueChange={(val) => {
											setSearchTerm(val);
											onSearch?.(val);
										}}
									/>
								)}

								<CommandList
									ref={commandListRef}
									className="max-h-[300px] overflow-y-auto "
								>
									{isLoading ? (
										<CommandEmpty>
											<LoadingSpinner />
										</CommandEmpty>
									) : displayedOptions.length === 0 && !isNullable ? (
										<CommandEmpty>
											No {label.toLowerCase()} found.
										</CommandEmpty>
									) : (
										<CommandGroup>
											{isNullable && (
												<CommandItem
													key="none"
													onSelect={() => {
														handleSelect(undefined);
														onChange?.(undefined);
													}}
													className="px-4 py-2 text-[16px] hover:bg-gray-200"
												>
													None
												</CommandItem>
											)}
											{displayedOptions.map((opt) => (
												<CommandItem
													key={opt.value}
													onSelect={() => handleSelect(opt.value)}
													className="px-4 py-2 text-[16px] hover:bg-gray-200"
												>
													{opt.label}
												</CommandItem>
											))}

											<div
												ref={sentinelRef}
												style={{
													height: '1px',
													position: 'relative',
													top: '100px',
												}}
											/>
											{isFetchingMore && (
												<div className="flex justify-center p-2">
													<LoadingSpinner />
												</div>
											)}
										</CommandGroup>
									)}
								</CommandList>
							</Command>
						</PopoverContent>
					</Popover>
				</div>
			)}
		/>
	);
};

export default RHFSelectWithSearch;
