import {
    useImperativeHandle,
    useLayoutEffect,
    forwardRef,
    useEffect,
    useState,
    type Ref,
    useRef
} from "react";
import {
    TouchableOpacity,
    type ViewStyle,
    View
} from "react-native";
import type {
    IMonthSelectorRef,
    CalendarMonth
} from "./type";
import type IMonthSelectorProps from "./type";
import stylesheet, {
    useStyles
} from "./stylesheet";
import {
    dateSelect
} from "./util";
import {
    NCoreUIKitLocalize,
    NCoreUIKitTheme,
    NCoreUIKitToast
} from "../../core/hooks";
import {
    type Mutable
} from "../../types";
import {
    ChevronRight as ChevronRightIcon,
    ChevronLeft as ChevronLeftIcon
} from "lucide-react-native";
import moment from "moment";
import {
    webStyle
} from "../../utils";
import Text from "../text";

const MONTH_LINES = [
    [
        0,
        1,
        2
    ],
    [
        3,
        4,
        5
    ],
    [
        6,
        7,
        8
    ],
    [
        9,
        10,
        11
    ]
];

const MonthSelector = ({
    multipleSelectMinimumRequiredDayCount,
    monthOfYearLengthType = "long",
    isShowTodayIndicator = true,
    multipleSelectDayLimit,
    setIsSheetContentReady,
    viewDate: viewDateProp,
    selectMultipleObject,
    selectObject,
    dateRange,
    maxDate,
    minDate,
    variant,
    date
}: IMonthSelectorProps, ref: Ref<IMonthSelectorRef>) => {
    const {
        radiuses,
        borders,
        spaces,
        colors
    } = NCoreUIKitTheme.useContext();

    const {
        localize
    } = NCoreUIKitLocalize.useContext();

    const selectDate = dateSelect({
        dateRange,
        variant,
        date
    });

    const [
        viewDate,
        setViewDate
    ] = useState(viewDateProp ? viewDateProp : selectDate);

    const [
        yearMonths,
        setYearMonths
    ] = useState<Array<CalendarMonth>>([]);

    const allSelectedMonths = useRef<Array<Date>>([]);

    const {
        nextPrevToolChevronButton: nextPrevToolChevronButtonDynamicStyle,
        nextPrevToolContainer: nextPrevToolContainerDynamicStyle,
        todayIndicator: todayIndicatorDynamicStyle,
        day: dayDynamicStyle
    } = useStyles({
        radiuses,
        borders,
        colors,
        spaces
    });

    useEffect(() => {
        const allMonths = getMonthsOfViewYear({
            tDate: viewDate
        });

        setYearMonths(allMonths);
    }, [
        dateRange,
        viewDate,
        date
    ]);

    useLayoutEffect(() => {
        if(yearMonths && yearMonths.length) setIsSheetContentReady(true);
    }, [
        yearMonths
    ]);

    useEffect(() => {
        if(viewDateProp) {
            setViewDate(viewDateProp);
        }
    }, [
        viewDateProp
    ]);

    useImperativeHandle(
        ref,
        () => ({
            changeCurrentYear: (date: Date) => {
                setViewDate(date);
            }
        }),
        []
    );

    const getMonthsOfViewYear = ({
        tDate
    }: {
        tDate: Date
    }): Array<CalendarMonth> => {
        allSelectedMonths.current = [];

        const targetDate = moment(new Date(tDate));

        const startOfCalendar = targetDate.clone().startOf("year");

        const months = monthOfYearLengthType === "short" ? moment.monthsShort() : moment.months();

        const totalMonths = months.length;

        const allMonths = Array.from({
            length: totalMonths
        }).map((_, index) => {
            const currentMonth = startOfCalendar.clone().add(index, "months");

            let isSelected = false;

            if(variant === "single" && date) {
                allSelectedMonths.current = [
                    date
                ];

                if(moment(currentMonth).isSame(date, "month")) isSelected = true;
            } else if(variant === "range" && dateRange && dateRange.start) {
                if(dateRange.end) {
                    allSelectedMonths.current = Array.from({
                        length: moment(dateRange.end).diff(dateRange.start, "months") + 1
                    }, (_, i) =>
                        moment(dateRange.start).clone().add(i, "months").toDate()
                    );

                    if(moment(currentMonth).isBetween(dateRange.start, dateRange.end, "month", "[]")) isSelected = true;
                } else if(moment(currentMonth).isSame(dateRange.start)) {
                    allSelectedMonths.current = [
                        dateRange.start
                    ];

                    isSelected = true;
                }
            }

            let isDisabled = false;

            if(minDate && moment(currentMonth).isBefore(moment(minDate).startOf("month"))) {
                isDisabled = true;
            }

            if(maxDate && moment(currentMonth).isAfter(moment(maxDate).endOf("month"))) {
                isDisabled = true;
            }

            const monthNumber = currentMonth.month();

            return {
                originalIndex: allSelectedMonths.current.findIndex((month) => moment(currentMonth).isSame(month, "month")),
                isCurrentYear: currentMonth.isSame(targetDate, "year"),
                isToday: currentMonth.isSame(moment(), "month"),
                title: months[monthNumber] as string,
                monthNumber: monthNumber + 1,
                monthOfYear: monthNumber,
                date: currentMonth,
                isDisabled,
                isSelected
            };
        });

        return allMonths;
    };

    const renderDay = ({
        monthIndex,
        monthItem
    }: {
        monthItem: CalendarMonth;
        monthIndex: number;
    }) => {
        const isLastItemSelected = monthItem.isSelected && monthItem.originalIndex === allSelectedMonths.current.length - 1;
        const isFirstItemSelected = monthItem.isSelected && monthItem.originalIndex === 0;

        const selectionStyle: Array<Mutable<ViewStyle> | null> = [
            isFirstItemSelected && allSelectedMonths.current.length > 1 ? {
                borderBottomRightRadius: 0,
                borderTopRightRadius: 0
            } : null,
            isLastItemSelected && allSelectedMonths.current.length > 1 ? {
                borderBottomLeftRadius: 0,
                borderTopLeftRadius: 0
            } : null
        ];

        let dayTitleColor: keyof NCoreUIKit.TextContentColors = "mid";

        if(monthItem.isSelected && !isLastItemSelected && !isFirstItemSelected) {
            dayTitleColor = "emphasized";

            selectionStyle.push({
                borderBottomRightRadius: 0,
                borderBottomLeftRadius: 0,
                borderTopRightRadius: 0,
                borderTopLeftRadius: 0
            });
        } else if(monthItem.isSelected) {
            dayTitleColor = "onPrimary";
        }

        if(!monthItem.isCurrentYear || monthItem.isDisabled) {
            dayTitleColor = "disabled";
        }

        return <TouchableOpacity
            onPress={() => {
                if(!monthItem.isCurrentYear) {
                    return;
                }

                if(variant === "single") {
                    const newDate = date as Date;

                    newDate.setMonth(monthItem.date.toDate().getMonth());

                    selectObject(newDate);
                } else if(variant === "range") {
                    if(!dateRange || !dateRange.start) {
                        selectMultipleObject({
                            start: new Date(monthItem.date.toDate().setHours(0, 0, 0)),
                            end: undefined
                        });
                        return;
                    }

                    if(dateRange && moment(dateRange.start).isSame(monthItem.date, "month")) {
                        selectMultipleObject({
                            start: undefined,
                            end: undefined
                        });
                        return;
                    }

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

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

                        if(moment(monthItem.date).isBefore(dateRange.start)) {
                            selectMultipleObject({
                                start: new Date(monthItem.date.toDate().setHours(0, 0, 0)),
                                end: undefined
                            });
                        } else {
                            selectMultipleObject({
                                end: new Date(monthItem.date.toDate().setHours(23, 59, 59)),
                                start: dateRange?.start
                            });
                        }
                        return;
                    }

                    selectMultipleObject({
                        start: monthItem.date.toDate(),
                        end: undefined
                    });
                }
            }}
            style={[
                stylesheet.day,
                dayDynamicStyle,
                monthItem.isSelected ? {
                    backgroundColor: colors.content.container.primary,
                    borderColor: colors.content.container.primary
                } : null,
                monthItem.isSelected && !isLastItemSelected && !isFirstItemSelected ? {
                    backgroundColor: colors.content.container.emphasized,
                    borderColor: colors.content.container.emphasized
                } : null,
                monthItem.isSelected && (monthItem.isDisabled || !monthItem.isCurrentYear) ? {
                    opacity: 0.33
                } : null,
                ...selectionStyle
            ]}
            disabled={!monthItem.isCurrentYear || monthItem.isDisabled}
            key={`month-${monthIndex}`}
        >
            <Text
                variant="labelLargeSize"
                color={dayTitleColor}
            >
                {monthItem.title}
            </Text>
            {
                isShowTodayIndicator && monthItem.isToday ?
                    <View
                        style={[
                            stylesheet.todayIndicator,
                            selectionStyle,
                            todayIndicatorDynamicStyle,
                    monthItem.isSelected ? {
                        borderColor: colors.content.border.subtle
                    } : null
                        ]}
                    />
                :
                    null
            }
        </TouchableOpacity>;
    };

    const renderNextPrevTool = () => {
        return <View
            style={[
                stylesheet.nextPrevToolContainer,
                nextPrevToolContainerDynamicStyle
            ]}
        >
            <TouchableOpacity
                onPress={() => {
                    const prevViewDate = moment(viewDate).clone().subtract(1, "years");
                    setViewDate(prevViewDate.toDate());
                }}
                style={[
                    nextPrevToolChevronButtonDynamicStyle
                ]}
            >
                <ChevronLeftIcon
                    color={colors.content.icon.default}
                    size={26}
                />
            </TouchableOpacity>
            <Text
                variant="labelLargeSize"
                color="high"
            >
                {moment(viewDate).format("YYYY")}
            </Text>
            <TouchableOpacity
                onPress={() => {
                    const nextViewDate = moment(viewDate).clone().add(1, "years");
                    setViewDate(nextViewDate.toDate());
                }}
                style={[
                    nextPrevToolChevronButtonDynamicStyle
                ]}
            >
                <ChevronRightIcon
                    color={colors.content.icon.default}
                    size={26}
                />
            </TouchableOpacity>
        </View>;
    };

    return <View
        style={[
            stylesheet.container
        ]}
    >
        <View>
            {renderNextPrevTool()}
        </View>
        <View
            style={[
                stylesheet.contentContainer
            ]}
        >
            {yearMonths && yearMonths.length ? MONTH_LINES.map((mItem, mIndex) => {
                const currentMonths = mItem.map(mI => yearMonths[mI]);

                return <View
                    style={[
                        stylesheet.rowContainer,
                        webStyle({
                            width: "100%"
                        })
                    ]}
                    key={`month-row-${mIndex}`}
                >
                    {currentMonths.map((monthItem, monthIndex) => {
                        return renderDay({
                            monthItem: monthItem as CalendarMonth,
                            monthIndex
                        });
                    })}
                </View>;
            }) : null}
        </View>
    </View>;
};
export default forwardRef(MonthSelector);
