import {
    useImperativeHandle,
    forwardRef,
    useEffect,
    useState,
    type Ref,
    useRef
} from "react";
import {
    TouchableOpacity,
    View
} from "react-native";
import {
    type SelectBoxComponent,
    type ISelectBoxRef,
    type SelectBoxType,
    type SelectedItem
} from "./type";
import type ISelectBoxProps from "./type";
import stylesheet, {
    getSelectBoxType,
    useStyles
} from "./stylesheet";
import {
    NCoreUIKitLocalize,
    NCoreUIKitTheme,
    NCoreUIKitToast
} from "../../core/hooks";
import {
    type NCoreUIKitIcon
} from "../../types";
import type {
    IBottomSheetRef
} from "../bottomSheet/type";
import type ITextProps from "../text/type";
import {
    BadgeQuestionMarkIcon,
    BadgeSuccessIcon,
    BadgeDangerIcon,
    BadgeAlertIcon,
    BadgeInfoIcon,
    CleanIcon
} from "../../assets/svg";
import {
    uuid
} from "../../utils";
import SelectSheet from "../selectSheet";
import Text from "../text";

const SelectBoxTypeIcon: Record<Exclude<SelectBoxType, "default">, NCoreUIKitIcon> = {
    "question": BadgeQuestionMarkIcon,
    "success": BadgeSuccessIcon,
    "warning": BadgeAlertIcon,
    "danger": BadgeDangerIcon,
    "info": BadgeInfoIcon
};

function SelectBox<T>({
    renderLoadingIcon : LoadingIconComponentProp,
    rightIcon: RightIconComponentProp,
    hintTextIcon: HintTextIconProp,
    isShowSelectSheetTools = true,
    spreadBehaviour = "baseline",
    isShowHintTextIcon = false,
    customSelectSheetLocalize,
    isWorkWithRealtime = true,
    isMultipleSelect = false,
    icon: IconComponentProp,
    hintTextContainerStyle,
    removeSelectValidation,
    customSelectSheetTheme,
    isCleanEnabled = false,
    contentContainerStyle,
    subTitle = "Optional",
    initialSelectedItems,
    isSearchable = false,
    onFocus: onFocusProp,
    isRequired = false,
    isDisabled = false,
    onBlur: onBlurProp,
    moreLoadThreshold,
    hintTextIconStyle,
    data: initialData,
    selectSheetProps,
    variant = "text",
    type = "default",
    rightIconOnPress,
    renderOptionIcon,
    selectValidation,
    customLocalize,
    rightIconStyle,
    isShowSubTitle,
    cleanIconStyle,
    titleExtractor,
    maxChoice = -1,
    keyExtractor,
    contentStyle,
    customTheme,
    placeholder,
    iconOnPress,
    onMoreLoad,
    isOptional,
    renderItem,
    customKey,
    minChoice,
    iconStyle,
    onChange,
    hintText,
    onSearch,
    style,
    title
}: ISelectBoxProps<T>, ref: Ref<ISelectBoxRef<T>>) {
    const {
        inlineSpaces,
        typography,
        radiuses,
        borders,
        spaces,
        colors
    } = NCoreUIKitTheme.useContext(customTheme);

    const {
        localize
    } = NCoreUIKitLocalize.useContext(customLocalize);

    const bottomSheetRef = useRef<IBottomSheetRef>(null);

    const selectBoxKey = useRef(customKey ? customKey : uuid());

    const currentType = getSelectBoxType({
        type
    });

    const styleType = type === "default" ? "neutral" : type === "question" ? "neutral" : type === "danger" ? "error" : type;

    const [
        data,
        setData
    ] = useState<Array<T & SelectedItem | SelectedItem>>([]);

    const [
        searchedData,
        setSearchedData
    ] = useState<Array<T & SelectedItem | SelectedItem>>([]);

    const [
        isActive,
        setIsActive
    ] = useState(false);

    const [
        searchText,
        setSearchText
    ] = useState("");

    const [
        isLoading,
        setIsLoading
    ] = useState(false);

    const [
        isMoreLoading,
        setIsMoreLoading
    ] = useState(true);

    const [
        selectedItems,
        setSelectedItems
    ] = useState<Array<SelectedItem>>(initialSelectedItems ?? []);

    const [
        tempSelectedItems,
        setTempSelectedItems
    ] = useState<Array<SelectedItem>>(initialSelectedItems ?? []);

    const mainSelectedItems = isWorkWithRealtime ? selectedItems : tempSelectedItems;

    const {
        contentContainer: contentContainerDynamicStyle,
        titleContainer: titleContainerDynamicStyle,
        hintTextIcon: hintTextIconDynamicStyle,
        contentText: contentTextDynamicStyle,
        cleanButton: cleanButtonDynamicStyle,
        rightIcon: rightIconDynamicStyle,
        container: containerDynamicStyle,
        hintText: hintTextDynamicStyle,
        required: requiredDynamicStyle,
        subTitle: subTitleDynamicStyle,
        overlay: overlayDynamicStyle,
        content: contentDynamicStyle,
        title: titleDynamicStyle,
        icon: iconDynamicStyle
    } = useStyles({
        icon: IconComponentProp ? true : false,
        spreadBehaviour,
        inlineSpaces,
        isSearchable,
        currentType,
        isDisabled,
        isActive,
        radiuses,
        borders,
        spaces,
        colors,
        title,
        type
    });

    useImperativeHandle(
        ref,
        () => ({
            setIsMoreLoading: (e) => setIsMoreLoading(e),
            setIsLoading: (e) => setIsLoading(e),
            updateSelections,
            cleanSelections,
            updateData,
            selectAll,
            cleanAll,
            cancel,
            focus,
            blur,
            ok
        }),
        []
    );

    useEffect(() => {
        if(isActive) {
            if(onFocus) onFocus();
        } else {
            if(!isWorkWithRealtime) {
                setTempSelectedItems([]);
            }

            setSearchText("");
            setSearchedData([]);

            setIsMoreLoading(false);

            if(onBlur) onBlur();
        }
    }, [isActive]);

    useEffect(() => {
        if(isSearchable && searchText && searchText.length) {
            if(onSearch) {
                const _searchedData = prepareDatas(onSearch({
                    selectedItems: mainSelectedItems,
                    setIsMoreLoading,
                    setIsLoading,
                    searchText,
                    data
                }) as Array<T & SelectedItem>, mainSelectedItems);

                setSearchedData(_searchedData);
            } else {
                const _searchedData = data.filter(dI => {
                    return dI.__title.toLocaleLowerCase().includes(searchText.toLocaleLowerCase());
                }) as Array<T & SelectedItem>;

                setSearchedData(_searchedData);
            }
        } else if(searchedData && searchedData.length) {
            setSearchedData([]);
        }
    }, [
        data,
        searchText
    ]);

    useEffect(() => {
        const initData = prepareDatas(initialData as Array<T & SelectedItem>, initialSelectedItems);

        setData(initData);
    }, []);

    const titleProps: ITextProps = {
        color: currentType.titleColor,
        variant: "bodyLargeSize"
    };

    const iconProps: NCoreUIKit.IconCallbackProps = {
        size: Number(typography.labelLargeSize.fontSize) + 6,
        color: currentType.iconColor
    };

    if(isDisabled) {
        iconProps.color = "disabled";
    }

    const blur = () => {
        setIsActive(false);
    };

    const focus = () => {
        if(!isWorkWithRealtime) {
            setTempSelectedItems(selectedItems);
        }

        setIsActive(true);
    };

    const cancel = () => {
        if(!isWorkWithRealtime) {
            bottomSheetRef.current?.close(() => {
                blur();
            });
        }
    };

    const ok = () => {
        if(!isWorkWithRealtime) {
            setSelectedItems(tempSelectedItems);

            bottomSheetRef.current?.close(() => {
                blur();
            });
        }
    };

    const cleanSelections = () => {
        setSelectedItems([]);

        if(!isWorkWithRealtime) {
            setTempSelectedItems([]);
        }

        if(onChange) {
            onChange([], data, setIsMoreLoading);
        }
    };

    const updateData = (newData: Array<T>, newSelectedItems: Array<SelectedItem>) => {
        const _newData = newData.map((bIItem, bIIndex) => {
            return {
                ...bIItem,
                __title: titleExtractor(bIItem as T & SelectedItem, bIIndex),
                __key: keyExtractor(bIItem as T & SelectedItem, bIIndex)
            };
        });

        setData(_newData);

        const _newSelectedItems = JSON.parse(JSON.stringify(newSelectedItems ? newSelectedItems : mainSelectedItems)).map((sItem: SelectedItem) => {
            const originalDataIndex = _newData.findIndex(ssItem => ssItem.__key === sItem.__key);

            return {
                __title: _newData[originalDataIndex]?.__title,
                __key: _newData[originalDataIndex]?.__key
            };
        });

        if(isWorkWithRealtime) {
            setSelectedItems(_newSelectedItems);
        } else {
            setTempSelectedItems(_newSelectedItems);
        }
    };

    const updateSelections = (newSelectedItems: Array<SelectedItem>) => {
        const _newSelectedItems = JSON.parse(JSON.stringify(newSelectedItems)).map((sItem: SelectedItem) => {
            const originalDataIndex = data.findIndex(ssItem => ssItem.__key === sItem.__key);

            return {
                ...sItem,
                __title: data[originalDataIndex]?.__title,
                __key: data[originalDataIndex]?.__key
            };
        });

        if(isWorkWithRealtime) {
            setSelectedItems(_newSelectedItems);
        } else {
            setTempSelectedItems(_newSelectedItems);
        }
    };

    const prepareDatas = (items: Array<T & SelectedItem>, sItems?: Array<SelectedItem>) => {
        const initData: Array<SelectedItem | T & SelectedItem> = [];

        if(sItems && sItems.length) {
            sItems.forEach((iS) => {
                const dataIndex = items.findIndex((iD, iDI) => keyExtractor(iD, iDI) === iS.__key);

                if(dataIndex === -1) {
                    initData.unshift(iS);
                }
            });
        }

        const finalData = items.map((bIItem, bIIndex) => {
            return {
                ...bIItem,
                __title: titleExtractor(bIItem, bIIndex),
                __key: keyExtractor(bIItem, bIIndex)
            };
        });

        return [
            ...initData,
            ...finalData
        ];
    };

    const selectObject = (selectedItem: T & SelectedItem | SelectedItem) => {
        const isAlreadySelected = mainSelectedItems.findIndex(sItem => sItem.__key === selectedItem.__key);
        let _selectedItems = JSON.parse(JSON.stringify(mainSelectedItems));

        if(isAlreadySelected !== -1) {
            let isProcessPerm = false;

            if(isMultipleSelect) {
                if(minChoice) {
                    if(_selectedItems.length > minChoice) {
                        isProcessPerm = true;
                    }
                } else {
                    isProcessPerm = true;
                }
            } else {
                const _minChoice = minChoice === undefined ? 0 : minChoice;

                if(_minChoice > 0) {
                    NCoreUIKitToast.open({
                        title: localize("minimum-a-item-selection-required")
                    });
                } else {
                    isProcessPerm = true;
                }
            }

            if(isProcessPerm) {
                if(removeSelectValidation) {
                    if(removeSelectValidation(selectedItem)) {
                        _selectedItems = _selectedItems.filter((sItem: SelectedItem) => sItem.__key !== selectedItem.__key);
                    }
                } else {
                    _selectedItems = _selectedItems.filter((sItem: SelectedItem) => sItem.__key !== selectedItem.__key);
                }
            }
        } else {
            let isProcessPerm = false;

            if(isMultipleSelect) {
                if(_selectedItems.length < maxChoice || maxChoice === -1) {
                    isProcessPerm = true;
                } else {
                    NCoreUIKitToast.open({
                        title: localize("maximum-selection-limit-has-been-reached")
                    });
                }
            } else {
                _selectedItems = [];
                isProcessPerm = true;
            }

            if(isProcessPerm) {
                if(selectValidation) {
                    if(selectValidation(selectedItem)) {
                        _selectedItems.push({
                            __title: selectedItem.__title,
                            __key: selectedItem.__key
                        });
                    }
                } else {
                    _selectedItems.push({
                        __title: selectedItem.__title,
                        __key: selectedItem.__key
                    });
                }
            }
        }

        if(isWorkWithRealtime) {
            setSelectedItems(_selectedItems);
        } else {
            setTempSelectedItems(_selectedItems);
        }
    };

    const cleanAll = () => {
        if(minChoice) {
            console.error("minChoice must be 0 or undefined for cleanAll function.");
            return;
        }

        if(isWorkWithRealtime) {
            setSelectedItems([]);
        } else {
            setTempSelectedItems([]);
        }
    };

    const selectAll = () => {
        if(maxChoice !== -1) {
            console.error("maxChoice must be -1 for selectAll function.");
            return;
        }

        const _selectedItems = JSON.parse(JSON.stringify(mainSelectedItems));

        if(searchText && searchText.length) {
            searchedData.forEach(searchedItem => {
                if(mainSelectedItems.findIndex(sI => sI.__key === searchedItem.__key) === -1) {
                    _selectedItems.push({
                        __title: searchedItem.__title,
                        __key: searchedItem.__key
                    });
                }
            });
        } else {
            data.forEach(dataItem => {
                if(mainSelectedItems.findIndex(sI => sI.__key === dataItem.__key) === -1) {
                    _selectedItems.push({
                        __title: dataItem.__title,
                        __key: dataItem.__key
                    });
                }
            });
        }

        if(isWorkWithRealtime) {
            setSelectedItems(_selectedItems);
        } else {
            setTempSelectedItems(_selectedItems);
        }
    };

    const onFocus = () => {
        if(onFocusProp) onFocusProp();
    };

    const onBlur = () => {
        if(onBlurProp) onBlurProp();
    };

    const renderCleanButton = () => {
        if(isDisabled) {
            return null;
        }

        if(variant !== "text") {
            return null;
        }

        if(!isCleanEnabled || !selectedItems.length) {
            return null;
        }

        return <TouchableOpacity
            style={[
                cleanIconStyle,
                stylesheet.cleanButton,
                cleanButtonDynamicStyle
            ]}
            onPress={() => {
                if(isWorkWithRealtime) {
                    setSelectedItems([]);
                } else {
                    setTempSelectedItems([]);
                }

                if(onChange) {
                    onChange([], data, setIsMoreLoading);
                }
            }}
        >
            <CleanIcon
                color="mid"
                size={20}
            />
        </TouchableOpacity>;
    };

    const renderIcon = () => {
        if (!IconComponentProp) {
            return null;
        }

        return <TouchableOpacity
            onPress={iconOnPress}
            style={[
                iconStyle,
                stylesheet.icon,
                iconDynamicStyle
            ]}
        >
            <IconComponentProp
                color={iconProps.color}
                size={iconProps.size}
            />
        </TouchableOpacity>;
    };

    const renderRightIcon = () => {
        if (!RightIconComponentProp) {
            return null;
        }

        if(isCleanEnabled && selectedItems.length > 0 && variant === "text") {
            return null;
        }

        return <TouchableOpacity
            onPress={rightIconOnPress}
            style={[
                rightIconStyle,
                stylesheet.rightIcon,
                rightIconDynamicStyle
            ]}
        >
            <RightIconComponentProp
                color={iconProps.color}
                size={iconProps.size}
            />
        </TouchableOpacity>;
    };

    const renderHintIcon = () => {
        if(!isShowHintTextIcon) {
            return null;
        }

        if(HintTextIconProp) {
            return <HintTextIconProp
                color={isDisabled ? "disabled" : currentType.hintTextIconColor}
                size={20}
                style={[
                    hintTextIconStyle,
                    stylesheet.hintTextIcon,
                    hintTextIconDynamicStyle
                ]}
            />;
        }

        const CurrentHintIcon = SelectBoxTypeIcon[type === "default" ? "question" : type];

        return <CurrentHintIcon
            customColor={isDisabled ? colors.system.state.content.disabled[styleType] : undefined}
            color={currentType.hintTextIconColor}
            size={20}
            style={[
                hintTextIconStyle,
                stylesheet.hintTextIcon,
                hintTextIconDynamicStyle
            ]}
        />;
    };

    const renderHintText = () => {
        if (!hintText) {
            return null;
        }

        return <View
            style={[
                hintTextContainerStyle,
                stylesheet.hintText,
                hintTextDynamicStyle
            ]}
        >
            {renderHintIcon()}
            <Text
                customColor={isDisabled ? colors.system.state.content.disabled[styleType] : undefined}
                color={currentType.hintTextColor}
                variant="labelSmallSize"
            >
                {hintText}
            </Text>
        </View>;
    };

    const renderRequired = () => {
        if(!isRequired) {
            return null;
        }

        return <Text
            color="danger"
            style={[
                stylesheet.required,
                requiredDynamicStyle
            ]}
        >*</Text>;
    };

    const renderSubtitle = () => {
        if(!isShowSubTitle && !isOptional) {
            return null;
        }

        return <Text
            variant="labelLargeSize"
            color={titleProps.color}
            style={[
                stylesheet.subTitle,
                subTitleDynamicStyle
            ]}
        >
            ( {isOptional ? localize("is-optional") : subTitle} )
        </Text>;
    };

    const renderTitle = () => {
        if (!title) {
            return null;
        }

        return <TouchableOpacity
            style={[
                stylesheet.titleContainer,
                titleContainerDynamicStyle
            ]}
            onPress={() => {
                if(!isDisabled) {
                    focus();
                }
            }}
        >
            {renderRequired()}
            <Text
                {...titleProps}
                variant={titleProps.variant}
                color={titleProps.color}
                style={[
                    stylesheet.title,
                    titleDynamicStyle
                ]}
            >
                {title}
            </Text>
            {renderSubtitle()}
        </TouchableOpacity>;
    };

    const renderValue = () => {
        if(!selectedItems.length) {
            return <Text
                variant="labelLargeSize"
                style={[
                    stylesheet.contentText,
                    contentTextDynamicStyle
                ]}
            >
                {placeholder ? placeholder : localize("select-an-option")}
            </Text>;
        }

        return <Text
            variant="labelLargeSize"
            style={[
                stylesheet.contentText,
                contentTextDynamicStyle
            ]}
        >
            {selectedItems.length > 1 ? localize("selected-options-with-count", [
                selectedItems.length
            ]) : selectedItems[0]?.__title}
        </Text>;
    };

    const renderContent = () => {
        return <View
            style={[
                contentStyle,
                stylesheet.content,
                contentDynamicStyle
            ]}
        >
            {renderValue()}
        </View>;
    };

    const renderOverlay = () => {
        return <View
            style={[
                stylesheet.overlay,
                overlayDynamicStyle
            ]}
        />;
    };

    return <View
        style={[
            style,
            stylesheet.container,
            containerDynamicStyle
        ]}
    >
        {renderTitle()}

        <TouchableOpacity
            disabled={isDisabled}
            style={[
                contentContainerStyle,
                stylesheet.contentContainer,
                contentContainerDynamicStyle
            ]}
            onPress={() => {
                if(!isDisabled) {
                    focus();
                }
            }}
        >
            {renderOverlay()}

            {renderIcon()}

            {renderContent()}

            {renderCleanButton()}
            {renderRightIcon()}
        </TouchableOpacity>

        {renderHintText()}

        <SelectSheet
            LoadingIconComponentProp={LoadingIconComponentProp}
            customLocalize={customSelectSheetLocalize}
            isWorkWithRealtime={isWorkWithRealtime}
            mainSelectedItems={mainSelectedItems}
            moreLoadThreshold={moreLoadThreshold}
            isShowTools={isShowSelectSheetTools}
            customTheme={customSelectSheetTheme}
            isMultipleSelect={isMultipleSelect}
            renderOptionIcon={renderOptionIcon}
            setIsMoreLoading={setIsMoreLoading}
            bottomSheetProps={selectSheetProps}
            selectBoxKey={selectBoxKey.current}
            bottomSheetRef={bottomSheetRef}
            setSearchText={setSearchText}
            isMoreLoading={isMoreLoading}
            searchedData={searchedData}
            isSearchable={isSearchable}
            keyExtractor={keyExtractor}
            selectObject={selectObject}
            setIsLoading={setIsLoading}
            setIsActive={setIsActive}
            searchText={searchText}
            renderItem={renderItem}
            onMoreLoad={onMoreLoad}
            maxChoice={maxChoice}
            minChoice={minChoice}
            isLoading={isLoading}
            selectAll={selectAll}
            cleanAll={cleanAll}
            isActive={isActive}
            cancel={cancel}
            title={title}
            data={data}
            ok={ok}
        />
    </View>;
};
export default forwardRef(SelectBox) as unknown as SelectBoxComponent;
