import React, { useMemo, useCallback, useRef, forwardRef } from "react"
import { atom, useAtom } from "jotai"
import { useVirtualizer } from "@tanstack/react-virtual"
import { Button, buttonVariants } from "@/components/ui/button"
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover"
import { cn } from "@/lib/utils"
import { LaIcon } from "@/components/custom/la-icon"
import { Command, CommandInput, CommandList, CommandItem, CommandGroup } from "@/components/ui/command"
import { useCoState } from "@/lib/providers/jazz-provider"
import { PublicGlobalGroup } from "@/lib/schema/master/public-group"
import { ListOfTopics, Topic } from "@/lib/schema"
import { JAZZ_GLOBAL_GROUP_ID } from "@/lib/constants"
import { VariantProps } from "class-variance-authority"

interface TopicSelectorProps extends VariantProps<typeof buttonVariants> {
	showSearch?: boolean
	defaultLabel?: string
	searchPlaceholder?: string
	value?: string | null
	onChange?: (value: string) => void
	onTopicChange?: (value: Topic) => void
	className?: string
	renderSelectedText?: (value?: string | null) => React.ReactNode
	side?: "bottom" | "top" | "right" | "left"
	align?: "center" | "end" | "start"
}

export const topicSelectorAtom = atom(false)

export const TopicSelector = forwardRef<HTMLButtonElement, TopicSelectorProps>(
	(
		{
			showSearch = true,
			defaultLabel = "Select topic",
			searchPlaceholder = "Search topic...",
			value,
			onChange,
			onTopicChange,
			className,
			renderSelectedText,
			side = "bottom",
			align = "end",
			...props
		},
		ref
	) => {
		const [isTopicSelectorOpen, setIsTopicSelectorOpen] = useAtom(topicSelectorAtom)
		const group = useCoState(PublicGlobalGroup, JAZZ_GLOBAL_GROUP_ID, { root: { topics: [] } })

		const handleSelect = useCallback(
			(selectedTopicName: string, topic: Topic) => {
				onChange?.(selectedTopicName)
				onTopicChange?.(topic)
				setIsTopicSelectorOpen(false)
			},
			[onChange, setIsTopicSelectorOpen, onTopicChange]
		)

		const displaySelectedText = useMemo(() => {
			if (renderSelectedText) {
				return renderSelectedText(value)
			}
			return <span className="truncate">{value || defaultLabel}</span>
		}, [value, defaultLabel, renderSelectedText])

		return (
			<Popover open={isTopicSelectorOpen} onOpenChange={setIsTopicSelectorOpen}>
				<PopoverTrigger asChild>
					<Button
						ref={ref}
						size="sm"
						type="button"
						role="combobox"
						variant="secondary"
						className={cn("gap-x-2 text-sm", className)}
						{...props}
					>
						{displaySelectedText}
						<LaIcon name="ChevronDown" />
					</Button>
				</PopoverTrigger>
				<PopoverContent
					className="w-52 rounded-lg p-0"
					side={side}
					align={align}
					onCloseAutoFocus={e => e.preventDefault()}
				>
					{group?.root.topics && (
						<TopicSelectorContent
							showSearch={showSearch}
							searchPlaceholder={searchPlaceholder}
							value={value}
							onSelect={handleSelect}
							topics={group.root.topics}
						/>
					)}
				</PopoverContent>
			</Popover>
		)
	}
)

TopicSelector.displayName = "TopicSelector"

interface TopicSelectorContentProps extends Omit<TopicSelectorProps, "onChange" | "onTopicChange"> {
	onSelect: (value: string, topic: Topic) => void
	topics: ListOfTopics
}

const TopicSelectorContent: React.FC<TopicSelectorContentProps> = React.memo(
	({ showSearch, searchPlaceholder, value, onSelect, topics }) => {
		const [search, setSearch] = React.useState("")
		const filteredTopics = useMemo(
			() => topics.filter(topic => topic?.prettyName.toLowerCase().includes(search.toLowerCase())),
			[topics, search]
		)

		const parentRef = useRef<HTMLDivElement>(null)

		const rowVirtualizer = useVirtualizer({
			count: filteredTopics.length,
			getScrollElement: () => parentRef.current,
			estimateSize: () => 35,
			overscan: 5
		})

		return (
			<Command>
				{showSearch && (
					<CommandInput placeholder={searchPlaceholder} className="h-9" value={search} onValueChange={setSearch} />
				)}
				<CommandList>
					<div ref={parentRef} style={{ height: "200px", overflow: "auto" }}>
						<div
							style={{
								height: `${rowVirtualizer.getTotalSize()}px`,
								width: "100%",
								position: "relative"
							}}
						>
							<CommandGroup>
								{rowVirtualizer.getVirtualItems().map(virtualRow => {
									const topic = filteredTopics[virtualRow.index]
									return (
										topic && (
											<CommandItem
												key={virtualRow.key}
												value={topic.name}
												onSelect={value => onSelect(value, topic)}
												style={{
													position: "absolute",
													top: 0,
													left: 0,
													width: "100%",
													height: `${virtualRow.size}px`,
													transform: `translateY(${virtualRow.start}px)`
												}}
											>
												<span>{topic.prettyName}</span>
												<LaIcon
													name="Check"
													className={cn("absolute right-3", topic.name === value ? "text-primary" : "text-transparent")}
												/>
											</CommandItem>
										)
									)
								})}
							</CommandGroup>
						</div>
					</div>
				</CommandList>
			</Command>
		)
	}
)

TopicSelectorContent.displayName = "TopicSelectorContent"

export default TopicSelector
