import { __read } from "tslib";
import React, { useState, useEffect } from "react";
import { formatISO8601ToDate } from "../utils/date";
import { monthsCalendar } from "./locale";
import { CalendarRoot } from "./styles";
import Header from "./components/Header";
import Months from "./components/Months";
import Years from "./components/Years";
import CalendarList from "./components/CalendarList";
import { datePattern } from "./constants";
var Calendar = function (_a) {
    var _b = _a.locale, locale = _b === void 0 ? "ru" : _b, _c = _a.isRangeMode, isRangeMode = _c === void 0 ? false : _c, _d = _a.hasButtons, hasButtons = _d === void 0 ? false : _d, _e = _a.date, date = _e === void 0 ? "" : _e, setDateToInput = _a.setDateToInput, closeCalendar = _a.closeCalendar, minDate = _a.minDate, maxDate = _a.maxDate, id = _a.id;
    var dateObject = new Date();
    var _f = __read(useState(0), 2), weekDayNumber = _f[0], setWeekDayNumber = _f[1];
    var _g = __read(useState(0), 2), daysInMonth = _g[0], setDaysInMonth = _g[1];
    var _h = __read(useState(0), 2), daysInPreviousMonth = _h[0], setDaysInPreviousMonth = _h[1];
    var _j = __read(useState(null), 2), chosenDate = _j[0], setChosenDate = _j[1];
    var _k = __read(useState(null), 2), chosenRange = _k[0], setChosenRange = _k[1];
    var _l = __read(useState(dateObject), 2), currentDate = _l[0], setCurrentDate = _l[1];
    var _m = __read(useState(2000), 2), currentYear = _m[0], setCurrentYear = _m[1];
    var _o = __read(useState(1), 2), currentMonth = _o[0], setCurrentMonth = _o[1];
    var _p = __read(useState(1), 2), currentDay = _p[0], setCurrentDay = _p[1];
    var _q = __read(useState("Январь"), 2), currentMonthName = _q[0], setCurrentMonthName = _q[1];
    var _r = __read(useState(), 2), endYearRange = _r[0], setEndYearRange = _r[1];
    var _s = __read(useState(false), 2), isMonthEditing = _s[0], setIsMonthEditing = _s[1];
    var _t = __read(useState(false), 2), isYearEditing = _t[0], setIsYearEditing = _t[1];
    var _u = __read(useState([]), 2), months = _u[0], setMonths = _u[1];
    var _v = __read(useState([]), 2), years = _v[0], setYears = _v[1];
    var _w = __read(useState(false), 2), isClosesCalendar = _w[0], setIsClosesCalendar = _w[1];
    var getAndSetCurrentDate = function (updatedDateObject) {
        if (updatedDateObject === void 0) { updatedDateObject = dateObject; }
        var year = updatedDateObject.getFullYear();
        var month = updatedDateObject.getMonth();
        var monthName = updatedDateObject.toLocaleString(locale, {
            month: "long"
        });
        var capitalizedMonth = monthName.charAt(0).toUpperCase() + monthName.slice(1);
        var day = updatedDateObject.getDate();
        setCurrentYear(year);
        setCurrentMonth(month);
        setCurrentMonthName(capitalizedMonth);
        setCurrentDay(day);
    };
    var getDaysInMonth = function (month) {
        return new Date(currentYear, month + 1, 0).getDate();
    };
    var getAvailableMonths = function () {
        if (minDate &&
            minDate.split(".")[2] === currentYear.toString() &&
            maxDate &&
            maxDate.split(".")[2] === currentYear.toString()) {
            var minMonth = Number(minDate.split(".")[1]) - 1;
            var maxMonth = Number(maxDate.split(".")[1]) - 1;
            return [minMonth, maxMonth];
        }
        else if (minDate && minDate.split(".")[2] === currentYear.toString()) {
            var minMonth = Number(minDate.split(".")[1]) - 1;
            return [minMonth, 11];
        }
        else if (maxDate && maxDate.split(".")[2] === currentYear.toString()) {
            var maxMonth = Number(maxDate.split(".")[1]) - 1;
            return [0, maxMonth];
        }
        else {
            return [0, 11];
        }
    };
    var getFormattedDateForCompare = function (_date) {
        if (_date) {
            var year = String(_date.getFullYear());
            var month = String(_date.getMonth() + 1);
            var day = String(_date.getDate());
            var formattedMonth = month.length < 2 ? "0" + month : month;
            var formattedDay = day.length < 2 ? "0" + day : day;
            return formattedMonth + "." + formattedDay + "." + year;
        }
        return null;
    };
    var getWeekdayOfFirstDayInMonth = function () {
        var firstDateOfMonth = new Date(currentYear, currentMonth, 1);
        var weekDay = firstDateOfMonth.getDay(); // return value 0 - 6 and value 0 === Sunday;
        if (locale === "en") {
            return weekDay;
        }
        else {
            weekDay = weekDay === 0 ? 6 : weekDay - 1;
            return weekDay;
        }
    };
    var changeMonthFromControl = function (changeType) {
        var newMonth = changeType === "next" ? currentMonth + 1 : currentMonth - 1;
        var daysCount = getDaysInMonth(newMonth);
        var day = currentDay > daysCount ? daysCount : currentDay;
        switch (changeType) {
            case "next":
                if (currentMonth === 11) {
                    setCurrentDate(new Date(currentYear + 1, 0, day));
                }
                else {
                    setCurrentDate(new Date(currentYear, newMonth, day));
                }
                break;
            case "previous":
                if (currentMonth === 0) {
                    setCurrentDate(new Date(currentYear - 1, 11, day));
                }
                else {
                    setCurrentDate(new Date(currentYear, newMonth, day));
                }
                break;
        }
    };
    var changeMonth = function (newMonth) {
        var daysCount = getDaysInMonth(newMonth);
        var day = currentDay > daysCount ? daysCount : currentDay;
        setCurrentDate(new Date(currentYear, newMonth, day));
        setIsMonthEditing(false);
    };
    var changeYear = function (newActiveYear) {
        setCurrentDate(new Date(newActiveYear, currentMonth, currentDay));
        setIsYearEditing(false);
    };
    var createYearsList = function (activeYear) {
        if (activeYear === void 0) { activeYear = dateObject.getFullYear(); }
        var minYear = minDate
            ? parseInt(minDate.split(".")[2], 10)
            : undefined;
        var maxYear = maxDate
            ? parseInt(maxDate.split(".")[2], 10)
            : undefined;
        return Array(9)
            .fill("")
            .map(function (_date, index) {
            if (index === 4) {
                return {
                    id: index + 1,
                    name: activeYear.toString(),
                    isActive: true,
                    isDisabled: false
                };
            }
            else {
                var _currentYear = activeYear + index - 4;
                return {
                    id: index + 1,
                    name: _currentYear.toString(),
                    isActive: false,
                    isDisabled: index === 12 - 1 ||
                        (!!minYear && _currentYear < minYear) ||
                        (!!maxYear && _currentYear > maxYear)
                };
            }
        });
    };
    var updateYearsData = function (yearsList) {
        setYears(yearsList);
        setEndYearRange(yearsList[yearsList.length - 2].name);
    };
    var onNext = function () {
        if (isYearEditing) {
            var nextDate = new Date(currentYear + 9, currentMonth, currentDay);
            var maxYear = maxDate
                ? Number(maxDate.split(".")[2])
                : undefined;
            if (maxYear && nextDate.getFullYear() > maxYear) {
                nextDate.setFullYear(maxYear);
                setCurrentDate(nextDate);
                return;
            }
            setCurrentDate(nextDate);
        }
        else {
            changeMonthFromControl("next");
        }
    };
    var onPrevious = function () {
        if (isYearEditing) {
            var previousDate = new Date(currentYear - 9, currentMonth, currentDay);
            var minYear = minDate
                ? Number(minDate.split(".")[2])
                : undefined;
            if (minYear && previousDate.getFullYear() < minYear) {
                previousDate.setFullYear(minYear);
                setCurrentDate(previousDate);
                return;
            }
            setCurrentDate(previousDate);
        }
        else {
            changeMonthFromControl("previous");
        }
    };
    var setRangeDate = function (_date) {
        if (Array.isArray(chosenRange) && chosenRange.length === 1) {
            var nextDate = formatISO8601ToDate(_date);
            var prevDate = formatISO8601ToDate(chosenRange[0]);
            var range = prevDate < nextDate ? [chosenRange[0], _date] : [_date, chosenRange[0]];
            setChosenRange(range);
        }
        else if (Array.isArray(chosenRange) && chosenRange.length === 2) {
            setChosenRange(null);
            setChosenRange([_date]);
        }
        else {
            setChosenRange([_date]);
        }
    };
    var chooseDate = function (_date) {
        if (isRangeMode) {
            setRangeDate(_date);
        }
        else {
            setChosenDate(_date);
        }
        var dateInArray = parseDateToArray(_date, true);
        var dateForInput = dateInArray[0] + "." + dateInArray[1] + "." + dateInArray[2];
        setDateToInput && setDateToInput(dateForInput);
    };
    var parseDateToArray = function (_date, isMonthFirst) {
        if (isMonthFirst === void 0) { isMonthFirst = false; }
        var dateInArray = _date.split(".");
        return isMonthFirst
            ? [dateInArray[1], dateInArray[0], dateInArray[2]]
            : [dateInArray[0], dateInArray[1], dateInArray[2]];
    };
    var setDateRangeFromInput = function (dateStart, dateEnd) {
        var dateStartParts = dateStart.split(".");
        var dateEndParts = dateEnd.split(".");
        var dayStart = parseInt(dateStartParts[0], 10);
        var monthStart = parseInt(dateStartParts[1], 10) - 1;
        var yearStart = parseInt(dateStartParts[2], 10);
        var dayEnd = parseInt(dateEndParts[0], 10);
        var monthEnd = parseInt(dateEndParts[1], 10) - 1;
        var yearEnd = parseInt(dateEndParts[2], 10);
        var dateStartInISO = new Date(yearStart, monthStart, dayStart);
        var dateEndInISO = new Date(yearEnd, monthEnd, dayEnd);
        var formattedDateStart = getFormattedDateForCompare(dateStartInISO);
        var formattedDateEnd = getFormattedDateForCompare(dateEndInISO);
        setChosenRange([formattedDateStart, formattedDateEnd]);
    };
    var setDateFromInput = function (_date) {
        var dateParts = _date.split(".");
        var day = parseInt(dateParts[0], 10);
        var month = parseInt(dateParts[1], 10) - 1;
        var year = parseInt(dateParts[2], 10);
        var dateInISO = new Date(year, month, day);
        var formattedDateForChoosing = getFormattedDateForCompare(dateInISO);
        setCurrentDate(dateInISO);
        chooseDate(formattedDateForChoosing);
    };
    var checkDateRangeFromInput = function (dateRange) {
        var dateRangeParts = dateRange.split(" / ");
        var dateStart = String(dateRangeParts[0]);
        var dateEnd = String(dateRangeParts[1]);
        if (datePattern.test(dateStart) && datePattern.test(dateEnd)) {
            setDateRangeFromInput(dateStart, dateEnd);
        }
    };
    var checkDateFromInput = function (_date) {
        if (datePattern.test(_date)) {
            setDateFromInput(_date);
        }
    };
    var handleCloseCalendar = function () {
        setIsClosesCalendar(true);
    };
    // Fill initial years & months list;
    useEffect(function () {
        var yearsList = createYearsList();
        var monthsArray = monthsCalendar[locale].map(function (month, index) { return ({
            id: index,
            name: month,
            isActive: currentMonthName === month,
            isDisabled: false
        }); });
        updateYearsData(yearsList);
        setMonths(monthsArray);
    }, []);
    // Update chosen date;
    useEffect(function () {
        getAndSetCurrentDate(currentDate);
    }, [currentDate]);
    // Update years list;
    useEffect(function () {
        if (years.length) {
            var weekday = getWeekdayOfFirstDayInMonth();
            var yearsList = createYearsList(currentYear);
            setWeekDayNumber(weekday);
            updateYearsData(yearsList);
        }
    }, [currentYear]);
    // Update month list;
    useEffect(function () {
        if (months.length) {
            var _a = __read(getAvailableMonths(), 2), minMonth_1 = _a[0], maxMonth_1 = _a[1];
            var weekday = getWeekdayOfFirstDayInMonth();
            var updatedMonths = months.map(function (_a) {
                var _id = _a.id, name = _a.name;
                return ({
                    id: _id,
                    name: name,
                    isActive: currentMonth === _id,
                    isDisabled: minMonth_1 > _id || _id > maxMonth_1
                });
            });
            setWeekDayNumber(weekday);
            setMonths(updatedMonths);
            setDaysInMonth(getDaysInMonth(currentMonth));
            setDaysInPreviousMonth(getDaysInMonth(currentMonth === 0 ? 11 : currentMonth - 1));
        }
    }, [currentMonth, currentYear]);
    // Control date prop from input;
    useEffect(function () {
        if (isRangeMode) {
            checkDateRangeFromInput(date);
        }
        else {
            checkDateFromInput(date);
        }
    }, [date]);
    useEffect(function () {
        if (isClosesCalendar) {
            closeCalendar === null || closeCalendar === void 0 ? void 0 : closeCalendar(isRangeMode ? chosenRange : chosenDate);
        }
    }, [chosenDate, isClosesCalendar, chosenRange]);
    return (React.createElement(CalendarRoot, { id: id },
        React.createElement(Header, { currentMonth: currentMonthName, currentYear: currentYear, yearEnd: endYearRange, isMonthEditing: isMonthEditing, isYearEditing: isYearEditing, setIsMonthEditing: setIsMonthEditing, setIsYearEditing: setIsYearEditing, onPrevious: onPrevious, onNext: onNext }),
        isMonthEditing && React.createElement(Months, { changeMonth: changeMonth, data: months }),
        isYearEditing && React.createElement(Years, { changeYear: changeYear, data: years }),
        !isMonthEditing && !isYearEditing && (React.createElement(CalendarList, { hasButtons: hasButtons, locale: locale, isRangeMode: isRangeMode, weekDayNumber: weekDayNumber, daysInMonth: daysInMonth, daysInPreviousMonth: daysInPreviousMonth, currentMonth: currentMonth, currentYear: currentYear, chosenDate: chosenDate, chooseDate: chooseDate, chosenRange: chosenRange, formattedDate: getFormattedDateForCompare, closeCalendar: handleCloseCalendar, minDate: minDate, maxDate: maxDate, onPrevious: onPrevious, onNext: onNext }))));
};
export default Calendar;
