import addDays from 'date-fns/addDays';
import addSeconds from 'date-fns/addSeconds';
import addMinutes from 'date-fns/addMinutes';
import addHours from 'date-fns/addHours';
import addWeeks from 'date-fns/addWeeks';
import addMonths from 'date-fns/addMonths';
import addYears from 'date-fns/addYears';
import differenceInYears from 'date-fns/differenceInYears';
import differenceInQuarters from 'date-fns/differenceInQuarters';
import differenceInMonths from 'date-fns/differenceInMonths';
import differenceInWeeks from 'date-fns/differenceInWeeks';
import differenceInDays from 'date-fns/differenceInDays';
import differenceInHours from 'date-fns/differenceInHours';
import differenceInMinutes from 'date-fns/differenceInMinutes';
import differenceInSeconds from 'date-fns/differenceInSeconds';
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds';
import eachDayOfInterval from 'date-fns/eachDayOfInterval';
import endOfDay from 'date-fns/endOfDay';
import endOfWeek from 'date-fns/endOfWeek';
import endOfYear from 'date-fns/endOfYear';
import format from 'date-fns/format';
import getDate from 'date-fns/getDate';
import getDay from 'date-fns/getDay';
import getDaysInMonth from 'date-fns/getDaysInMonth';
import getHours from 'date-fns/getHours';
import getMinutes from 'date-fns/getMinutes';
import getMonth from 'date-fns/getMonth';
import getSeconds from 'date-fns/getSeconds';
import getYear from 'date-fns/getYear';
import isAfter from 'date-fns/isAfter';
import isBefore from 'date-fns/isBefore';
import isEqual from 'date-fns/isEqual';
import isSameDay from 'date-fns/isSameDay';
import isSameYear from 'date-fns/isSameYear';
import isSameMonth from 'date-fns/isSameMonth';
import isSameHour from 'date-fns/isSameHour';
import isValid from 'date-fns/isValid';
import dateFnsParse from 'date-fns/parse';
import setDate from 'date-fns/setDate';
import setHours from 'date-fns/setHours';
import setMinutes from 'date-fns/setMinutes';
import setMonth from 'date-fns/setMonth';
import setSeconds from 'date-fns/setSeconds';
import setYear from 'date-fns/setYear';
import startOfDay from 'date-fns/startOfDay';
import startOfMonth from 'date-fns/startOfMonth';
import endOfMonth from 'date-fns/endOfMonth';
import startOfWeek from 'date-fns/startOfWeek';
import startOfYear from 'date-fns/startOfYear';
import parseISO from 'date-fns/parseISO';
import formatISO from 'date-fns/formatISO';
import isWithinInterval from 'date-fns/isWithinInterval';
import longFormatters from 'date-fns/_lib/format/longFormatters';
import defaultLocale from 'date-fns/locale/en-US';

var defaultFormats = {
    dayOfMonth: "d",
    fullDate: "PP",
    fullDateWithWeekday: "PPPP",
    fullDateTime: "PP p",
    fullDateTime12h: "PP hh:mm aaa",
    fullDateTime24h: "PP HH:mm",
    fullTime: "p",
    fullTime12h: "hh:mm aaa",
    fullTime24h: "HH:mm",
    hours12h: "hh",
    hours24h: "HH",
    keyboardDate: "P",
    keyboardDateTime: "P p",
    keyboardDateTime12h: "P hh:mm aaa",
    keyboardDateTime24h: "P HH:mm",
    minutes: "mm",
    month: "LLLL",
    monthAndDate: "MMMM d",
    monthAndYear: "LLLL yyyy",
    monthShort: "MMM",
    weekday: "EEEE",
    weekdayShort: "EEE",
    normalDate: "d MMMM",
    normalDateWithWeekday: "EEE, MMM d",
    seconds: "ss",
    shortDate: "MMM d",
    year: "yyyy",
};
var DateFnsUtils = /** @class */ (function () {
    function DateFnsUtils(_a) {
        var _this = this;
        var _b = _a === void 0 ? {} : _a, locale = _b.locale, formats = _b.formats;
        this.lib = "date-fns";
        // Note: date-fns input types are more lenient than this adapter, so we need to expose our more
        // strict signature and delegate to the more lenient signature. Otherwise, we have downstream type errors upon usage.
        this.is12HourCycleInCurrentLocale = function () {
            if (_this.locale) {
                return /a/.test(_this.locale.formatLong.time());
            }
            // By default date-fns is using en-US locale with am/pm enabled
            return true;
        };
        this.getFormatHelperText = function (format) {
            // @see https://github.com/date-fns/date-fns/blob/master/src/format/index.js#L31
            var longFormatRegexp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;
            var locale = _this.locale || defaultLocale;
            return format
                .match(longFormatRegexp)
                .map(function (token) {
                var firstCharacter = token[0];
                if (firstCharacter === "p" || firstCharacter === "P") {
                    var longFormatter = longFormatters[firstCharacter];
                    return longFormatter(token, locale.formatLong, {});
                }
                return token;
            })
                .join("")
                .replace(/(aaa|aa|a)/g, "(a|p)m")
                .toLocaleLowerCase();
        };
        this.parseISO = function (isoString) {
            return parseISO(isoString);
        };
        this.toISO = function (value) {
            return formatISO(value, { format: "extended" });
        };
        this.getCurrentLocaleCode = function () {
            var _a;
            return ((_a = _this.locale) === null || _a === void 0 ? void 0 : _a.code) || "en-US";
        };
        this.addSeconds = function (value, count) {
            return addSeconds(value, count);
        };
        this.addMinutes = function (value, count) {
            return addMinutes(value, count);
        };
        this.addHours = function (value, count) {
            return addHours(value, count);
        };
        this.addDays = function (value, count) {
            return addDays(value, count);
        };
        this.addWeeks = function (value, count) {
            return addWeeks(value, count);
        };
        this.addMonths = function (value, count) {
            return addMonths(value, count);
        };
        this.addYears = function (value, count) {
            return addYears(value, count);
        };
        this.isValid = function (value) {
            return isValid(_this.date(value));
        };
        this.getDiff = function (value, comparing, unit) {
            switch (unit) {
                case "years":
                    return differenceInYears(value, _this.date(comparing));
                case "quarters":
                    return differenceInQuarters(value, _this.date(comparing));
                case "months":
                    return differenceInMonths(value, _this.date(comparing));
                case "weeks":
                    return differenceInWeeks(value, _this.date(comparing));
                case "days":
                    return differenceInDays(value, _this.date(comparing));
                case "hours":
                    return differenceInHours(value, _this.date(comparing));
                case "minutes":
                    return differenceInMinutes(value, _this.date(comparing));
                case "seconds":
                    return differenceInSeconds(value, _this.date(comparing));
                default: {
                    return differenceInMilliseconds(value, _this.date(comparing));
                }
            }
        };
        this.isAfter = function (value, comparing) {
            return isAfter(value, comparing);
        };
        this.isBefore = function (value, comparing) {
            return isBefore(value, comparing);
        };
        this.startOfDay = function (value) {
            return startOfDay(value);
        };
        this.endOfDay = function (value) {
            return endOfDay(value);
        };
        this.getHours = function (value) {
            return getHours(value);
        };
        this.setHours = function (value, count) {
            return setHours(value, count);
        };
        this.setMinutes = function (value, count) {
            return setMinutes(value, count);
        };
        this.getSeconds = function (value) {
            return getSeconds(value);
        };
        this.setSeconds = function (value, count) {
            return setSeconds(value, count);
        };
        this.isSameDay = function (value, comparing) {
            return isSameDay(value, comparing);
        };
        this.isSameMonth = function (value, comparing) {
            return isSameMonth(value, comparing);
        };
        this.isSameYear = function (value, comparing) {
            return isSameYear(value, comparing);
        };
        this.isSameHour = function (value, comparing) {
            return isSameHour(value, comparing);
        };
        this.startOfYear = function (value) {
            return startOfYear(value);
        };
        this.endOfYear = function (value) {
            return endOfYear(value);
        };
        this.startOfMonth = function (value) {
            return startOfMonth(value);
        };
        this.endOfMonth = function (value) {
            return endOfMonth(value);
        };
        this.startOfWeek = function (value) {
            return startOfWeek(value, { locale: _this.locale });
        };
        this.endOfWeek = function (value) {
            return endOfWeek(value, { locale: _this.locale });
        };
        this.getYear = function (value) {
            return getYear(value);
        };
        this.setYear = function (value, count) {
            return setYear(value, count);
        };
        this.date = function (value) {
            if (typeof value === "undefined") {
                return new Date();
            }
            if (value === null) {
                return null;
            }
            return new Date(value);
        };
        this.toJsDate = function (value) {
            return value;
        };
        this.parse = function (value, formatString) {
            if (value === "") {
                return null;
            }
            return dateFnsParse(value, formatString, new Date(), { locale: _this.locale });
        };
        this.format = function (date, formatKey) {
            return _this.formatByString(date, _this.formats[formatKey]);
        };
        this.formatByString = function (date, formatString) {
            return format(date, formatString, { locale: _this.locale });
        };
        this.isEqual = function (date, comparing) {
            if (date === null && comparing === null) {
                return true;
            }
            return isEqual(date, comparing);
        };
        this.isNull = function (date) {
            return date === null;
        };
        this.isAfterDay = function (date, value) {
            return isAfter(date, endOfDay(value));
        };
        this.isBeforeDay = function (date, value) {
            return isBefore(date, startOfDay(value));
        };
        this.isBeforeYear = function (date, value) {
            return isBefore(date, startOfYear(value));
        };
        this.isAfterYear = function (date, value) {
            return isAfter(date, endOfYear(value));
        };
        this.isWithinRange = function (date, _a) {
            var start = _a[0], end = _a[1];
            return isWithinInterval(date, { start: start, end: end });
        };
        this.formatNumber = function (numberToFormat) {
            return numberToFormat;
        };
        this.getMinutes = function (date) {
            return getMinutes(date);
        };
        this.getDate = function (date) {
            return getDate(date);
        };
        this.setDate = function (date, count) {
            return setDate(date, count);
        };
        this.getMonth = function (date) {
            return getMonth(date);
        };
        this.getDaysInMonth = function (date) {
            return getDaysInMonth(date);
        };
        this.setMonth = function (date, count) {
            return setMonth(date, count);
        };
        this.getMeridiemText = function (ampm) {
            return ampm === "am" ? "AM" : "PM";
        };
        this.getNextMonth = function (date) {
            return addMonths(date, 1);
        };
        this.getPreviousMonth = function (date) {
            return addMonths(date, -1);
        };
        this.getMonthArray = function (date) {
            var firstMonth = startOfYear(date);
            var monthArray = [firstMonth];
            while (monthArray.length < 12) {
                var prevMonth = monthArray[monthArray.length - 1];
                monthArray.push(_this.getNextMonth(prevMonth));
            }
            return monthArray;
        };
        this.mergeDateAndTime = function (date, time) {
            return _this.setSeconds(_this.setMinutes(_this.setHours(date, _this.getHours(time)), _this.getMinutes(time)), _this.getSeconds(time));
        };
        this.getWeekdays = function () {
            var now = new Date();
            return eachDayOfInterval({
                start: startOfWeek(now, { locale: _this.locale }),
                end: endOfWeek(now, { locale: _this.locale }),
            }).map(function (day) { return _this.formatByString(day, "EEEEEE"); });
        };
        this.getWeekArray = function (date) {
            var start = startOfWeek(startOfMonth(date), { locale: _this.locale });
            var end = endOfWeek(endOfMonth(date), { locale: _this.locale });
            var count = 0;
            var current = start;
            var nestedWeeks = [];
            var lastDay = null;
            while (isBefore(current, end)) {
                var weekNumber = Math.floor(count / 7);
                nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
                var day = getDay(current);
                if (lastDay !== day) {
                    lastDay = day;
                    nestedWeeks[weekNumber].push(current);
                    count += 1;
                }
                current = addDays(current, 1);
            }
            return nestedWeeks;
        };
        this.getYearRange = function (start, end) {
            var startDate = startOfYear(start);
            var endDate = endOfYear(end);
            var years = [];
            var current = startDate;
            while (isBefore(current, endDate)) {
                years.push(current);
                current = addYears(current, 1);
            }
            return years;
        };
        this.locale = locale;
        this.formats = Object.assign({}, defaultFormats, formats);
    }
    return DateFnsUtils;
}());

export { DateFnsUtils as default };
