import React, { useState, useEffect, useRef } from 'react';
import { motion, Variants } from 'framer-motion';
import { Icon, SearchNormal } from 'iconsax-react';
import clsx from 'clsx';
import { ChevronDown } from 'lucide-react';

export interface ComboboxOption {
    id: string;
    title: string;
    icon?: Icon;
    label?: string;
}

type Props = {
    title: string;
    options: Array<ComboboxOption>;
    expanded?: boolean;
    selectedId: string;
    searchable?: boolean;
    placeholder?: string;
    icon?: React.ElementType;
    onSelectionChange: (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => void,
} & React.HTMLAttributes<HTMLDivElement>

function Combobox({ title, options, placeholder, icon: Icon, expanded, selectedId, searchable = true, onSelectionChange, ...props }: Props) {
    const [expand, setExpand] = useState(expanded);
    const [searchValue, setSearchValue] = useState('');
    const boxRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
            if (boxRef.current && !boxRef.current.contains(event.target as Node)) {
                setExpand(false);
            }
        };

        if (expand) {
            document.addEventListener('mousedown', handleClickOutside);
        }

        return () => {
            document.removeEventListener('mousedown', handleClickOutside);
        };
    }, [expand]);

    const toggleExpand = () => {
        setExpand((prev) => !prev);
        setSearchValue('');
    };

    const searchChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
        setSearchValue(e.target.value);
    };

    const setSelection = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => {
        e.stopPropagation(); // prevent toggle
        onSelectionChange(e, index);
        setExpand(false);
    };

    const selectedOption = options.find((x) => x.id === selectedId);
    const activeIcon = selectedOption?.icon && React.createElement(selectedOption.icon, {
        size: 16,
        className: "inline-block mr-1 stroke-primary"
    })


    const variants: Variants = {
        collapse: {
            opacity: 0,
            scale: 0.95,
            pointerEvents: 'none',     // disable clicks
            transition: {
                duration: 0.1,
                ease: 'easeInOut'
            }
        },
        expand: {
            opacity: 1,
            scale: 1,
            pointerEvents: 'auto',     // re-enable clicks
            transition: {
                duration: 0.1,
                ease: 'easeInOut'
            }
        }
    };


    return (
        <div ref={boxRef}
            className={clsx(
                "relative",
                props.className ?? '')}
            {...props}
        >
            <div
                className="flex w-full h-11 items-center justify-end gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer"
                tabIndex={0}
                onClick={toggleExpand}
                role="combobox"
                aria-controls=''
                aria-expanded={expand}
                aria-haspopup="listbox"
                aria-label={title}
            >
                <label
                    htmlFor="content-select"
                    className="pointer-events-none inline-flex flex-col items-end justify-center px-1 py-0 absolute -top-6 right-0 z-[2]"
                >
                    <span className="relative w-fit mt-[-1px] text-xs tracking-[0] leading-4 whitespace-nowrap">
                        {title}
                    </span>
                </label>

                <div className="w-full text-sm2 flex items-center justify-start gap-3">
                    {
                        activeIcon ? (
                            activeIcon
                        ) : (
                            Icon && <Icon size={16} className="inline-block mr-1 stroke-primary" />
                        )
                    }
                    <span className={clsx(
                        selectedOption?.title ? "mt-0.5" : "mt-1 text-sm font-light"
                    )}
                    >
                        {selectedOption?.title ?? placeholder}
                    </span>
                </div>

                <ChevronDown size={20} data-expand={expand} className="transition-all stroke-foreground duration-200 data-[expand=true]:rotate-x-180" />
            </div>

            <motion.div
                data-expand={expand}
                aria-hidden={!expand}
                className="absolute top-full left-0 w-full mt-1 text-foreground bg-white rounded-xl outline outline-solid outline-neutral-200 shadow-lg z-10"
                role="listbox"
                aria-label={`${title} options`}
                onClick={(e) => e.stopPropagation()}
                initial="collapse"
                animate={expand ? "expand" : "collapse"}
                variants={variants}
            >

                {searchable &&
                    <div className="w-full flex gap-2 border-b px-3 items-center">
                        <SearchNormal size={16} className='stroke-gray-400' />
                        <input
                            placeholder="جستجو ..."
                            className="w-full outline-none text-sm2 pb-2 pt-3"
                            onChange={searchChanged}
                            value={searchValue}
                        />
                    </div>
                }
                <div className='p-1'>
                    {options
                        .filter((v) => v.title?.includes(searchValue))
                        .map((v, i) => (
                            <div
                                onClick={(e) => setSelection(e, i)}
                                key={v.id}
                                data-selected={v.id === selectedId}
                                className="flex gap-3 items-center justify-end px-2 py-1 cursor-pointer hover:bg-gray-50 rounded-md last:rounded-b-xl"
                                tabIndex={0}
                                role="option"
                                aria-selected
                            >
                                {
                                    v?.icon && React.createElement(v.icon, {
                                        size: 16,
                                        className: "inline-block mr-1 stroke-primary"
                                    })
                                }
                                <span className="text-sm2 tracking-[0.13px] leading-5 w-full mt-1">{v.title}</span>
                            </div>
                        ))}
                </div>
            </motion.div>
        </div>
    );
}


export default Combobox