import {
    useImperativeHandle,
    forwardRef,
    useEffect,
    useState,
    type Ref,
    useRef
} from "react";
import {
    TouchableOpacity,
    View
} from "react-native";
import type IDateTimePickerProps from "./type";
import type {
    DateTimePickerDateRange,
    IDateTimePickerRef,
    DateTimePickerType
} from "./type";
import stylesheet, {
    getDateTimePickerType,
    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 {
    type RRule as RRuleType,
    RRule
} from "rrule";
import moment from "moment";
import {
    BadgeQuestionMarkIcon,
    BadgeSuccessIcon,
    BadgeDangerIcon,
    BadgeAlertIcon,
    BadgeInfoIcon,
    CleanIcon
} from "../../assets/svg";
import {
    uuid
} from "../../utils";
import Text from "../text";
import DateTimeSheet from "../dateTimeSheet";
import {
    parseRRuleConfig
} from "../../helpers";

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

const DateTimePicker = ({
    isTimeSelectWorksWithCenterWhenTimePicker = true,
    renderLoadingIcon : LoadingIconComponentProp,
    multipleSelectMinimumRequiredDayCount,
    isStartDateSelectionRequired = true,
    rightIcon: RightIconComponentProp,
    isEndDateSelectionRequired = true,
    localeBasedFirstDayOfWeek = true,
    isShowCalenderChangerTool = true,
    monthOfYearLengthType = "short",
    multipleSelectMinimumRequireMS,
    hintTextIcon: HintTextIconProp,
    spreadBehaviour = "baseline",
    customDateTimeSheetLocalize,
    isShowTodayIndicator = true,
    titleFormat = "DD MMM YYYY",
    isShowDateTimeTools = true,
    isShowHintTextIcon = false,
    isWorkWithRealtime = true,
    dayOfWeekLength = "short",
    isWorkWithSeconds = false,
    customDateTimeSheetTheme,
    pickerType = "date-time",
    multipleSelectMaximumMS,
    icon: IconComponentProp,
    hintTextContainerStyle,
    removeSelectValidation,
    isCleanEnabled = false,
    multipleSelectDayLimit,
    contentContainerStyle,
    subTitle = "Optional",
    isSearchable = false,
    onFocus: onFocusProp,
    isRequired = false,
    isDisabled = false,
    onBlur: onBlurProp,
    dateTimeSheetProps,
    variant = "single",
    hintTextIconStyle,
    dateCalendarType,
    initialDateRange,
    type = "default",
    selectValidation,
    initialDateRule,
    dateRangeTitle,
    customLocalize,
    rightIconStyle,
    isShowSubTitle,
    cleanIconStyle,
    maxChoice = -1,
    returnFormat,
    contentStyle,
    initialDate,
    customTheme,
    placeholder,
    isOptional,
    customKey,
    minChoice,
    iconStyle,
    onChange,
    hintText,
    onCancel,
    maxDate,
    minDate,
    style,
    title,
    onOk
}: IDateTimePickerProps, ref: Ref<IDateTimePickerRef>) => {
    const {
        inlineSpaces,
        typography,
        radiuses,
        borders,
        spaces,
        colors
    } = NCoreUIKitTheme.useContext(customTheme);

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

    const bottomSheetRef = useRef<IBottomSheetRef>(null);

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

    const currentType = getDateTimePickerType({
        type
    });

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

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

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

    const [
        tempDate,
        setTempDate
    ] = useState<Date | undefined>(initialDate);

    const [
        date,
        setDate
    ] = useState<Date | undefined>(initialDate);

    const [
        tempDateRule,
        setTempDateRule
    ] = useState<RRuleType | undefined>(initialDateRule);

    const [
        dateRule,
        setDateRule
    ] = useState<RRuleType | undefined>(initialDateRule);

    const [
        dateRange,
        setDateRange
    ] = useState<DateTimePickerDateRange | undefined>(initialDateRange);

    const [
        tempDateRange,
        setTempDateRange
    ] = useState<DateTimePickerDateRange | undefined>(initialDateRange);

    const mainDateRange = isWorkWithRealtime ? dateRange : tempDateRange;
    const mainDateRule = isWorkWithRealtime ? dateRule : tempDateRule;
    const mainDate = isWorkWithRealtime ? date : tempDate;

    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,
        () => ({
            setDateRange: (dateRange) => {
                if(isWorkWithRealtime) {
                    setDateRange(dateRange);
                } else {
                    setTempDateRange(dateRange);
                }
            },
            setDateRule: (dateRule) => {
                if(isWorkWithRealtime) {
                    setDateRule(dateRule);
                } else {
                    setTempDateRule(dateRule);
                }
            },
            setDate: (date) => {
                if(isWorkWithRealtime) {
                    setDate(date);
                } else {
                    setTempDate(date);
                }
            },
            setIsLoading: setIsLoading,
            getValue: () => {
                return {
                    dateRange,
                    dateRule,
                    date
                };
            },
            cancel,
            clean,
            focus,
            blur,
            ok
        }),
        [
            dateRange,
            dateRule,
            date
        ]
    );

    useEffect(() => {
        if(isActive) {
            if(onFocus) onFocus();
        } else {
            if(!isWorkWithRealtime) {
                setTempDateRange(undefined);
                setTempDateRule(undefined);
                setTempDate(undefined);
            }

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

    useEffect(() => {
        if(onChange) {
            const resp = getFormattedResponse();
            onChange(resp);
        }
    }, [
        tempDateRange,
        tempDateRule,
        dateRange,
        dateRule,
        tempDate,
        date
    ]);

    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 getFormattedResponse = () => {
        if(returnFormat) {
            const _date = date ? moment(date).format(returnFormat) : undefined;

            const _dateRange: {
                start?: Date | string;
                end?: Date | string;
            } | undefined = dateRange;

            if(_dateRange && _dateRange.start) {
                _dateRange.start = moment(_dateRange.start).format(returnFormat);
            }

            if(_dateRange && _dateRange.end) {
                _dateRange.end = moment(_dateRange.end).format(returnFormat);
            }

            return {
                dateRange: _dateRange,
                date: _date,
                dateRule
            };
        } else {
            return {
                dateRange,
                dateRule,
                date
            };
        }
    };

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

    const focus = () => {
        if(!isWorkWithRealtime) {
            setTempDateRange(dateRange);
            setTempDateRule(dateRule);
            setTempDate(date);
        }

        setIsActive(true);
    };

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

            if(onCancel) {
                const resp = getFormattedResponse();
                onCancel(resp);
            }
        }
    };

    const ok = () => {
        if(!isWorkWithRealtime) {
            if(variant === "range") {
                if(isStartDateSelectionRequired && (!tempDateRange || !tempDateRange.start)) {
                    NCoreUIKitToast.open({
                        title: localize("start-date-select-is-required")
                    });
                    return;
                }

                if(isEndDateSelectionRequired && (!tempDateRange || !tempDateRange.end)) {
                    NCoreUIKitToast.open({
                        title: localize("end-date-select-is-required")
                    });
                    return;
                }

                if(tempDateRange && tempDateRange.start && tempDateRange.end) {
                    if(multipleSelectDayLimit && moment(tempDateRange.end).diff(tempDateRange.start, "days") >= multipleSelectDayLimit) {
                        NCoreUIKitToast.open({
                            title: localize("maximum-selection-number-of-days-limit-exceeds")
                        });
                        return;
                    }

                    if(multipleSelectMinimumRequiredDayCount && moment(tempDateRange.end).diff(tempDateRange.start, "days") + 1 < multipleSelectMinimumRequiredDayCount) {
                        NCoreUIKitToast.open({
                            title: localize("minimum-selection-number-of-days-required-not-provided")
                        });
                        return;
                    }
                }
            }

            setDateRange(tempDateRange);
            setDateRule(tempDateRule);
            setDate(tempDate);

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

            if(onOk) {
                const resp = getFormattedResponse();
                onOk(resp);
            }
        }
    };

    const clean = () => {
        setDateRange(undefined);
        setDateRule(undefined);
        setDate(undefined);

        setTempDateRange(undefined);
        setTempDateRule(undefined);
        setTempDate(undefined);
    };

    const selectDateRule = (selectedDateRule?: RRule) => {
        if(variant === "rrule") {
            if(selectedDateRule && selectedDateRule !== dateRule) {
                if(selectValidation) {
                    if(selectValidation({
                        dateRule: selectedDateRule
                    })) {
                        if(isWorkWithRealtime) {
                            setDateRule(selectedDateRule);
                        } else {
                            setTempDateRule(selectedDateRule);
                        }
                    }
                } else {
                    if(isWorkWithRealtime) {
                        setDateRule(selectedDateRule);
                    } else {
                        setTempDateRule(selectedDateRule);
                    }
                }
            } else {
                if(removeSelectValidation) {
                    if(removeSelectValidation({
                        dateRule
                    })) {
                        setTempDateRule(undefined);
                        setDateRule(undefined);
                    }
                } else {
                    setTempDateRule(undefined);
                    setDateRule(undefined);
                }
            }
        }
    };

    const selectMultipleObject = (selectedDateRange?: {
        start?: Date;
        end?: Date;
    }) => {
        if(variant === "range") {
            if(selectedDateRange) {
                if(selectValidation) {
                    if(selectValidation({
                        dateRule
                    })) {
                        if(isWorkWithRealtime) {
                            setDateRange({
                                start: selectedDateRange.start,
                                end: selectedDateRange.end
                            });
                        } else {
                            setTempDateRange({
                                start: selectedDateRange.start,
                                end: selectedDateRange.end
                            });
                        }
                    }
                } else {
                    if(isWorkWithRealtime) {
                        setDateRange({
                            start: selectedDateRange.start,
                            end: selectedDateRange.end
                        });
                    } else {
                        setTempDateRange({
                            start: selectedDateRange.start,
                            end: selectedDateRange.end
                        });
                    }
                }
            } else {
                if(removeSelectValidation) {
                    if(removeSelectValidation({
                        dateRange: selectedDateRange
                    })) {
                        setTempDateRange(undefined);
                        setDateRange(undefined);
                    }
                } else {
                    setTempDateRange(undefined);
                    setDateRange(undefined);
                }
            }
        }
    };

    const selectObject = (selectedDate?: Date) => {
        if(variant === "single") {
            if(selectedDate === date) {
                if(removeSelectValidation) {
                    if(removeSelectValidation({
                        date
                    })) {
                        if(isWorkWithRealtime) {
                            setDate(undefined);
                        } else {
                            setTempDate(undefined);
                        }
                    }
                } else {
                    if(isWorkWithRealtime) {
                        setDate(undefined);
                    } else {
                        setTempDate(undefined);
                    }
                }
            } else {
                if(selectValidation) {
                    if(selectValidation({
                        date
                    })) {
                        if(isWorkWithRealtime) {
                            setDate(selectedDate);
                        } else {
                            setTempDate(selectedDate);
                        }
                    }
                } else {
                    if(isWorkWithRealtime) {
                        setDate(selectedDate);
                    } else {
                        setTempDate(selectedDate);
                    }
                }
            }
        }
    };

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

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

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

        if(!isCleanEnabled) {
            return null;
        }

        if(variant === "rrule") {
            if(!mainDateRule) return null;
        } else if(variant === "range") {
            if(!dateRange) return null;
        } else {
            if(!date) return null;
        }

        return <TouchableOpacity
            style={[
                cleanIconStyle,
                stylesheet.cleanButton,
                cleanButtonDynamicStyle
            ]}
            onPress={() => {
                setDateRange(undefined);
                setDateRule(undefined);
                setDate(undefined);

                setTempDateRange(undefined);
                setTempDateRule(undefined);
                setTempDate(undefined);
            }}
        >
            <CleanIcon
                color="mid"
                size={20}
            />
        </TouchableOpacity>;
    };

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

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

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

        if(isCleanEnabled) {
            return null;
        }

        if(variant === "rrule") {
            if(!mainDateRule) return null;
        } else if(variant === "range") {
            if(!mainDateRange) return null;
        } else {
            if(!mainDate) return null;
        }

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

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

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

        const CurrentHintIcon = DateTimePickerTypeIcon[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 renderDateValue = () => {
        if(!date) {
            return <Text
                variant="labelLargeSize"
                numberOfLines={1}
                style={[
                    stylesheet.contentText,
                    contentTextDynamicStyle
                ]}
            >
                {placeholder ? placeholder : localize("select-any-date")}
            </Text>;
        }

        return <Text
            variant="labelLargeSize"
            numberOfLines={1}
            style={[
                stylesheet.contentText,
                contentTextDynamicStyle
            ]}
        >
            {moment(date).format(titleFormat)}
        </Text>;
    };

    const renderDateRangeValue = () => {
        if(!dateRange) {
            return <Text
                variant="labelLargeSize"
                numberOfLines={1}
                style={[
                    stylesheet.contentText,
                    contentTextDynamicStyle
                ]}
            >
                {placeholder ? placeholder : localize("select-any-date")}
            </Text>;
        }

        if(dateRangeTitle) {
            return dateRangeTitle(dateRange);
        }

        return <Text
            variant="labelLargeSize"
            numberOfLines={1}
            style={[
                stylesheet.contentText,
                contentTextDynamicStyle
            ]}
        >
            {moment(dateRange.start).format(titleFormat)} - {moment(dateRange.end).format(titleFormat)}
        </Text>;
    };

    const renderDateRuleValue = () => {
        if(!dateRule) {
            return <Text
                variant="labelLargeSize"
                numberOfLines={1}
                style={[
                    stylesheet.contentText,
                    contentTextDynamicStyle
                ]}
            >
                {placeholder ? placeholder : localize("select-any-date")}
            </Text>;
        }

        return <Text
            variant="labelLargeSize"
            numberOfLines={1}
            style={[
                stylesheet.contentText,
                contentTextDynamicStyle
            ]}
        >
            {dateRule.toText(undefined, parseRRuleConfig(rruleConfig))}
        </Text>;
    };

    const renderValue = () => {
        if(variant === "rrule") {
            return renderDateRuleValue();
        }

        if(variant === "range") {
            return renderDateRangeValue();
        }

        return renderDateValue();
    };

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

        <DateTimeSheet
            isTimeSelectWorksWithCenterWhenTimePicker={isTimeSelectWorksWithCenterWhenTimePicker}
            multipleSelectMinimumRequiredDayCount={multipleSelectMinimumRequiredDayCount}
            multipleSelectMinimumRequireMS={multipleSelectMinimumRequireMS}
            localeBasedFirstDayOfWeek={localeBasedFirstDayOfWeek}
            isShowCalenderChangerTool={isShowCalenderChangerTool}
            LoadingIconComponentProp={LoadingIconComponentProp}
            multipleSelectMaximumMS={multipleSelectMaximumMS}
            multipleSelectDayLimit={multipleSelectDayLimit}
            dateTimePickerKey={dateTimePickerKey.current}
            monthOfYearLengthType={monthOfYearLengthType}
            customLocalize={customDateTimeSheetLocalize}
            selectMultipleObject={selectMultipleObject}
            isShowTodayIndicator={isShowTodayIndicator}
            isWorkWithRealtime={isWorkWithRealtime}
            customTheme={customDateTimeSheetTheme}
            isWorkWithSeconds={isWorkWithSeconds}
            dateCalendarType={dateCalendarType}
            isShowTools={isShowDateTimeTools}
            dayOfWeekLength={dayOfWeekLength}
            bottomSheetRef={bottomSheetRef}
            selectDateRule={selectDateRule}
            selectObject={selectObject}
            setIsActive={setIsActive}
            bottomSheetProps={{
                isAutoHeight: true,
                ...dateTimeSheetProps
            }}
            dateRange={mainDateRange}
            pickerType={pickerType}
            maxChoice={maxChoice}
            minChoice={minChoice}
            isLoading={isLoading}
            dateRule={dateRule}
            isActive={isActive}
            variant={variant}
            maxDate={maxDate}
            minDate={minDate}
            date={mainDate}
            cancel={cancel}
            clean={clean}
            title={title}
            ok={ok}
        />
    </View>;
};
export default forwardRef(DateTimePicker);
