import React, {ReactElement, useEffect, useRef, useState} from "react";
import open from '../../../../assets/images/down-arrow.svg';
import './customselect.scss'
import close from '../../../../assets/images/close.svg';
import closeWhite from '../../../../assets/images/close-white.svg';
import CustomTextField from "../CustomTextField/CustomTextField";
import {extractPlainTextFromChild} from "../../../../helpers/functions";
import {SelectGroupProps} from "./SelectGroup";
import {SelectItemProps} from "./SelectItem";
import DownArrow from "../../../SVG/DownArrow";

interface BaseProps {
    handleChange: (n: any) => void
    placeholder?: string
    children: Array<ReactElement<SelectGroupProps | SelectItemProps>>
    disabled?: boolean
    onUnmount?: () => void
    onMount?: () => void
    isLoading?: boolean
    theme?: 'user-form-select' | 'per-page' | 'search-listbox' | 'search-listbox-blue'
    hasError?: string
    isForGate?: boolean
    clearable?: boolean
    searchable?: boolean
    minSearch?: number
    arrowDown?:boolean
    /** Fired on every keystroke in the search input with the raw query string.
     * Lets the parent drive server-side search (e.g. only fetch once "@" is typed)
     * while this component still does its own client-side filtering of whatever
     * children it currently has. */
    onSearchChange?: (query: string) => void
    /** Overrides the default "Δεν υπάρχουν αποτελέσματα" text shown when there are
     * zero matching children. Useful when the parent is doing server-side search
     * and wants to show e.g. "type an email to search" or "searching..." instead. */
    emptyMessage?: string
}

interface CustomSelectSingle extends BaseProps {
    multiple?: false | undefined,
    value: string | number | null
}

interface CustomSelectMultiple extends BaseProps {
    multiple: true,
    value: string[] | number[] | null[]
}

export type CustomSelectProps = CustomSelectSingle | CustomSelectMultiple

export default function CustomSelect({arrowDown =false,
                                         onMount,
                                         onUnmount,
                                         placeholder = 'Επιλέξτε',
                                         value,
                                         disabled = false,
                                         children,
                                         handleChange,
                                         isLoading = false,
                                         theme = 'user-form-select',
                                         hasError = '',
                                         clearable = false,
                                         searchable,
                                         minSearch = 0,
                                         multiple,
                                         onSearchChange,
                                         emptyMessage = 'Δεν υπάρχουν αποτελέσματα',
                                     }: CustomSelectProps) {

    const [isOpen, setIsOpen] = useState(false)
    const selectRef = useRef(null)
    const [searchQuery, setSearchQuery] = useState('');
    const [focusedChild, setFocusedChild] = useState(-1)

    const updateSearchQuery = (s: string) => {
        setSearchQuery(s)
        onSearchChange && onSearchChange(s)
    }

    let hasGroups = false;

    const handleOptionClick = (v: string | number | null) => {
        if (!multiple) {
            handleChange(v)
        } else {
            const newValue = [...value]
            const index = newValue.indexOf(v);
            index > -1 ? newValue.splice(index, 1) : newValue.push(v)
            handleChange(newValue)
        }
    }

    /**
     * transform the select item to
     * 1 filter them base on search criteria
     * 2 add checkbox for multiselect
     */
    const makeFilteredChild = (child: ReactElement<SelectItemProps>) => {
        if (React.isValidElement(child)) {
            /**
             * if select is not searchable allways match the child
             */
            const isMatch = searchable ?
                searchQuery.length >= minSearch && extractPlainTextFromChild(child).toLowerCase().includes(searchQuery.toLowerCase())
                :
                true

            if (isMatch) {
                filteredCount++
                selectItemsCount++
                const thisValue = child.props.value
                return React.cloneElement(child, {
                    active: filteredCount === focusedChild,
                    checkbox: multiple,
                    // @ts-ignore
                    selected: multiple && Array.isArray(value) && value.includes(thisValue),
                    onClick: () => {
                        updateSearchQuery("")
                        handleOptionClick(thisValue)
                    },
                    ...child.props,
                });
            }
        }
    }

    let filteredCount = -1 //used for highlighting the correct item when navigating with arrows
    let selectItemsCount = 0

    const filteredChildren = React.Children.map(children, (child, i) => {
        if (!React.isValidElement(child)) return null;

        const typeName = (child.type as any)?.displayName;
        if (typeName === 'SelectItem') {
            return makeFilteredChild(child as ReactElement<SelectItemProps>)
        } else if (typeName === 'SelectGroup') {
            hasGroups = true
            const group = child as ReactElement<SelectGroupProps>
            return React.cloneElement(group, {
                children: React.Children.map(group.props.children, (cc) => {
                    return makeFilteredChild(cc as ReactElement<SelectItemProps>)
                }),
                key: `group-${i}`
            })
        }
        return null
    });

    useEffect(() => {
        if (!isOpen) {
            setFocusedChild(-1)
        }

        const handleClick = (e: any) => {
            if (isOpen) {
                if (e.source && e.source.current === selectRef.current) return
                setIsOpen(false)
                updateSearchQuery('')
            }
        }
        window.addEventListener('click', handleClick)
        return () => {
            window.removeEventListener('click', handleClick)
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isOpen]);

    useEffect(() => {
        onMount && onMount()
        return () => {
            onUnmount && onUnmount()
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    let selectedChild: string[] = [];
    children?.forEach((c: ReactElement<SelectGroupProps | SelectItemProps>) => {
        if (!React.isValidElement(c)) return;
        const typeName = (c.type as any)?.displayName;

        if (typeName === 'SelectItem') {
            const item = c as ReactElement<SelectItemProps>;
            if (multiple ? (value as any[]).includes(item.props.value) : item.props.value == value) {
                selectedChild.push(extractPlainTextFromChild(item))
            }
        } else if (typeName === 'SelectGroup') {
            const group = c as ReactElement<SelectGroupProps>
            React.Children.forEach(group.props.children, (cc) => {
                if (!React.isValidElement(cc)) return;
                const childItem = cc as ReactElement<SelectItemProps>
                if (multiple ? (value as any[]).includes(childItem.props.value) : childItem.props.value == value) {
                    selectedChild.push(extractPlainTextFromChild(childItem))
                }
            })
        }
    })
    const arrowColor = theme === 'search-listbox' ? 'white' : '#707070'
    return (
        <>
            <div className={`custom-select ${theme} ${hasError && 'hasError'}`}>
                <div ref={selectRef}
                     className={`select-head ${disabled && 'disabled'} ${isLoading && 'loading'} ${selectedChild && 'hasSelected'}`}
                     onClick={(e) => {
                         if (isLoading) return
                         // @ts-ignore
                         e.nativeEvent.source = selectRef
                         setIsOpen(!isOpen)
                     }}>

                    {/* Multiple mode: chips + search input */}
                    {multiple ? (
                        <div className="selected-tags-with-input">
                            <div className="selected-tags">
                                {React.Children.map(children, (c) => {
                                    if (!React.isValidElement(c)) return null;
                                    const typeName = (c.type as any)?.displayName;

                                    if (typeName === 'SelectItem') {
                                        const item = c as ReactElement<SelectItemProps>
                                        // @ts-ignore
                                        if (value.includes(item.props.value)) {
                                            return (
                                                <span key={item.props.value} className="tag">
                                    {extractPlainTextFromChild(item)}
                                                    {!disabled &&
                                                        <img
                                                            src={closeWhite}
                                                            alt="remove"
                                                            onClick={(e) => {
                                                                e.stopPropagation()
                                                                handleOptionClick(item.props.value)
                                                            }}
                                                        />}
                                </span>
                                            )
                                        }
                                    } else if (typeName === 'SelectGroup') {
                                        const group = c as ReactElement<SelectGroupProps>
                                        return React.Children.map(group.props.children, (cc) => {
                                            if (!React.isValidElement(cc)) return null;
                                            const childItem = cc as ReactElement<SelectItemProps>
                                            // @ts-ignore
                                            if (value.includes(childItem.props.value)) {
                                                return (
                                                    <span key={childItem.props.value} className="tag">
                                        {extractPlainTextFromChild(childItem)}
                                                        {!disabled &&
                                                            <img
                                                                src={closeWhite}
                                                                alt="remove"
                                                                onClick={(e) => {
                                                                    e.stopPropagation()
                                                                    handleOptionClick(childItem.props.value)
                                                                }}
                                                            />}
                                    </span>
                                                )
                                            }
                                            return null
                                        })
                                    }
                                    return null
                                })}
                            </div>

                            {/* ✅ Search input always visible for multiple */}
                            {searchable && (
                                <CustomTextField
                                    readOnly={disabled}
                                    placeholder={placeholder}
                                    onChange={(s) => {
                                        updateSearchQuery(s)
                                        setFocusedChild(-1)
                                        s.length > 0 && !isOpen && setIsOpen(true)
                                    }}
                                    autoComplete={'off'}
                                    value={
                                        searchable && isOpen
                                            ? searchQuery
                                            : selectedChild.join(', ')
                                    }
                                    onKeyDown={(e: any) => {
                                        if (e.key === 'Tab') {
                                            updateSearchQuery('')
                                            setIsOpen(false)
                                        }
                                        if (e.key === 'ArrowDown') {
                                            setFocusedChild(Math.min(selectItemsCount - 1, focusedChild + 1))
                                        }
                                        if (e.key === 'ArrowUp') {
                                            setFocusedChild(Math.max(0, focusedChild - 1))
                                        }
                                        if (e.key === 'Enter') {
                                            if (hasGroups) return
                                            // @ts-ignore
                                            handleOptionClick(filteredChildren![focusedChild].props.value)
                                            updateSearchQuery('')
                                            e.preventDefault()
                                            e.target.blur()
                                        }
                                    }}
                                />
                            )}
                        </div>
                    ) : (
                        // single-select
                        <CustomTextField
                            readOnly={!searchable || disabled}
                            title={selectedChild.length > 0 ? selectedChild.join(',') : ''}
                            placeholder={selectedChild.length > 0 ? selectedChild.join(',') : placeholder}
                            onChange={(s) => {
                                if (!searchable) return
                                updateSearchQuery(s)
                                setFocusedChild(-1)
                                s.length > 0 && !isOpen && setIsOpen(true)
                            }}
                            autoComplete={'off'}
                            value={searchQuery || (selectedChild.length > 0 ? selectedChild.join(',') : '')}
                        />
                    )}

                    {/* buttons (clear/arrow) stay same */}
                    <div className="buttons">
                        {clearable && selectedChild.length > 0 && (
                            <img src={close} className={'close'}
                                 onClick={(e) => {
                                     e.stopPropagation()
                                     handleChange(multiple ? [] : 0)
                                 }}
                            />
                        )}
                        {!searchable && <img src={open} className={'open'}/>}
                        {arrowDown &&
                            <span className={"down-arrow"}>
            <DownArrow color={arrowColor}/>
        </span>}
                    </div>
                </div>

                {
                    isOpen && !disabled &&
                    <ul className="options">
                        <div className="options-inner">
                            {
                                searchable && searchQuery.length < minSearch ?
                                    <li style={{pointerEvents: 'none'}}>Εισάγετε τουλάχιστον {minSearch} χαρακτήρες</li>
                                    :
                                    <>
                                        {filteredChildren?.length > 0 ?
                                            filteredChildren
                                            :
                                            <li style={{pointerEvents: 'none'}}>{emptyMessage}</li>
                                        }
                                    </>
                            }
                        </div>
                    </ul>
                }
            </div>
            {
                hasError && <p className={'error-message'}>{hasError}</p>
            }
        </>
    );
}