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


export interface CustomSelectProps {
    placeholder?: string
    children: Array<ReactElement<SelectGroupProps | SelectItemProps>>
    disabled?: boolean
    handleChange: (n: any) => void
    onUnmount?: () => void
    value: string | number | Array<any>
    isLoading?: boolean
    theme?: 'user-form-select' | 'form'
    hasError?: string
    isForGate?: boolean
    clearable?: boolean
    searchable?: boolean
    minSearch?: number
    multiple?: boolean

}


export default function CustomSelect({
                                         onUnmount,
                                         placeholder = 'Επιλέξτε',
                                         value,
                                         disabled = false,
                                         children,
                                         handleChange,
                                         isLoading = false,
                                         theme = 'user-form-select',
                                         hasError = '',
                                         clearable = false,
                                         searchable,
                                         minSearch = 3,
                                         multiple = false
                                     }: CustomSelectProps) {

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


    const handleOptionClick = (v: string) => {
        if (!multiple) {
            handleChange(v)
        }
        //Value is an Array
        else {
            const newValue = [...value as Array<string>]
            const index = newValue.indexOf(v);
            index > -1 ? newValue.splice(index, 1) : newValue.push(v)
            handleChange(newValue)
        }


    }


    const makeFilteredChild = (child: ReactElement<SelectGroupProps | SelectItemProps>) => {
        if (React.isValidElement(child)) {

            // const plainText = extractPlainTextFromChild(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++
                // @ts-ignore
                const thisValue = child.props?.value
                return React.cloneElement(child, {
                    active: filteredCount === focusedChild,
                    checkbox: multiple,
                    selected: multiple && Array.isArray(value) && value.includes(thisValue),
                    onClick: () => {
                        setSearchQuery("")
                        handleOptionClick(thisValue)
                        // handleChange(child.props!.value)
                    },
                    ...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) => {

        // @ts-ignore
        if (child.type?.displayName === 'SelectItem') {
            return makeFilteredChild(child)
        }
        // @ts-ignore
        else if(child.type?.displayName === 'SelectGroup') {
            /**
             * incase of select group map and transform thew children of the select group
             */
            // @ts-ignore
            return React.cloneElement(child, {
                // @ts-ignore
                children: child?.props?.children.map((child: ReactElement) => {
                    return makeFilteredChild(child)
                }),
                key: `group-${i}`
            });
        }
        else{
        }
    });


    useEffect(() => {

        if (!isOpen) {
            setFocusedChild(-1)
        }

        const handleClick = (e: any) => {
            if (isOpen) {
                if (e.source && e.source.current === selectRef.current) return
                setIsOpen(false)
                setSearchQuery('')
            }
        }
        window.addEventListener('click', handleClick)
        return () => {
            window.removeEventListener('click', handleClick)
        }
    }, [isOpen]);

    /**
     * method to run on unmount
     */
    useEffect(() => {
        return () => {
            onUnmount && onUnmount()
        }
    }, [])


    /**
     * search for selected child on top level and 1 level deep incase of selectgroup.
     */
    let selectedChild: string[] = [];
    children?.forEach((c: ReactElement<SelectGroupProps | SelectItemProps>) => {
        // @ts-ignore
        if (c.type?.displayName === 'SelectItem') {
            // @ts-ignore
            if (multiple ? value.includes(c.props?.value) : c.props?.value == value) selectedChild.push(extractPlainTextFromChild(c))
        } else {
            // @ts-ignore
            c.props.children.forEach(cc => {
                // @ts-ignore
                if (multiple ? value.includes(cc.props?.value) : cc.props?.value == value) selectedChild.push(extractPlainTextFromChild(cc))
            })
        }

    })

    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)
                     }}>

                    <CustomTextField
                        readOnly={!searchable}
                        placeholder={selectedChild.length > 0 ? selectedChild.join(',') : placeholder}
                        onChange={(s) => {
                            if (!searchable) return
                            setSearchQuery(s)
                            setFocusedChild(-1)
                            s.length > 0 && !isOpen && setIsOpen(true)
                        }}
                        theme={'user-form-field'}
                        autoComplete={'off'}
                        value={searchQuery}
                        onKeyDown={(e: any) => {
                            if (e.key === 'Tab') {
                                setSearchQuery('')
                                setIsOpen(false)
                            }
                            if (e.key === 'ArrowDown') {
                                setFocusedChild(Math.min(selectItemsCount - 1, focusedChild + 1))
                                // e.preventDefault()
                                // e.stopPropagation()
                            }
                            if (e.key === 'ArrowUp') {
                                setFocusedChild(Math.max(0, focusedChild - 1))
                                // e.preventDefault()
                                // e.stopPropagation()
                            }
                            if (e.key === 'Enter') {
                                // @ts-ignore
                                handleChange(filteredChildren![focusedChild].props.value)
                                setSearchQuery('')
                                setIsOpen(false)
                                e.preventDefault()
                                e.target.blur()
                            }

                        }}
                    />

                    <div className="buttons">
                        {

                            clearable && selectedChild.length > 0 &&
                            <img src={close} className={'close'}
                                 onClick={
                                     (e) => {
                                         e.stopPropagation()
                                         handleChange('')
                                     }
                                 }/>
                        }

                        {
                            !searchable && <img src={open} className={'open'}/>
                        }
                    </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'}}>Δεν υπάρχουν αποτελέσματα</li>
                                        }
                                    </>

                            }
                        </div>
                    </ul>


                }

            </div>
            {
                hasError && <p className={'error-message'}>{hasError}</p>
            }
        </>

    );
}
