"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get ISO9075_DATETIME_FORMAT () {
        return ISO9075_DATETIME_FORMAT;
    },
    get ISO9075_DATE_FORMAT () {
        return ISO9075_DATE_FORMAT;
    },
    get PLAIN_TIME_PATTERN () {
        return PLAIN_TIME_PATTERN;
    },
    get ageInMonths () {
        return ageInMonths;
    },
    get ageInWeeks () {
        return ageInWeeks;
    },
    get ageInYears () {
        return ageInYears;
    },
    get convertISO9075toRFC3339 () {
        return convertISO9075toRFC3339;
    },
    get dateCustomValidation () {
        return dateCustomValidation;
    },
    get datetimeCustomValidation () {
        return datetimeCustomValidation;
    },
    get differenceInMilliseconds () {
        return differenceInMilliseconds;
    },
    get doAgeRangesHaveGaps () {
        return doAgeRangesHaveGaps;
    },
    get doAgeRangesOverlap () {
        return doAgeRangesOverlap;
    },
    get eachDayInMonth () {
        return eachDayInMonth;
    },
    get endpointsOfDay () {
        return endpointsOfDay;
    },
    get format () {
        return format;
    },
    get formatSurveyTimeFromDate () {
        return formatSurveyTimeFromDate;
    },
    get getCurrentDateString () {
        return getCurrentDateString;
    },
    get getCurrentDateStringInTimezone () {
        return getCurrentDateStringInTimezone;
    },
    get getCurrentDateTimeString () {
        return getCurrentDateTimeString;
    },
    get getCurrentDateTimeStringInTimezone () {
        return getCurrentDateTimeStringInTimezone;
    },
    get getCurrentISO8601DateString () {
        return getCurrentISO8601DateString;
    },
    get getDateTimeSubtractedFromNow () {
        return getDateTimeSubtractedFromNow;
    },
    get getDayBoundaries () {
        return getDayBoundaries;
    },
    get getFacilityNowDate () {
        return getFacilityNowDate;
    },
    get intlFormatDate () {
        return intlFormatDate;
    },
    get isISO9075DateString () {
        return isISO9075DateString;
    },
    get isISOString () {
        return isISOString;
    },
    get isIntervalWithinInterval () {
        return isIntervalWithinInterval;
    },
    get isStartOfThisWeek () {
        return isStartOfThisWeek;
    },
    get isValidSurveyTimeBody () {
        return isValidSurveyTimeBody;
    },
    get isWithinIntervalExcludingEnd () {
        return isWithinIntervalExcludingEnd;
    },
    get locale () {
        return locale;
    },
    get maxValidDate () {
        return maxValidDate;
    },
    get minValidDate () {
        return minValidDate;
    },
    get parseDate () {
        return parseDate;
    },
    get parseSurveyTimeToHHmmss () {
        return parseSurveyTimeToHHmmss;
    },
    get storedDateTimeToEpochMilliseconds () {
        return storedDateTimeToEpochMilliseconds;
    },
    get timeCustomValidation () {
        return timeCustomValidation;
    },
    get toDateString () {
        return toDateString;
    },
    get toDateTimeString () {
        return toDateTimeString;
    },
    get toFacilityDateTime () {
        return toFacilityDateTime;
    },
    get toStoredDateTime () {
        return toStoredDateTime;
    },
    get toWeekdayCode () {
        return toWeekdayCode;
    },
    get trimToDate () {
        return trimToDate;
    },
    get trimToTime () {
        return trimToTime;
    }
});
const _datefns = require("date-fns");
const _temporalpolyfill = require("temporal-polyfill");
const _zod = require("zod");
const _constants = require("@tamanu/constants");
const ISO9075_DATE_FORMAT = 'yyyy-MM-dd';
const ISO9075_DATETIME_FORMAT = 'yyyy-MM-dd HH:mm:ss';
const isISOString = (dateString)=>(0, _datefns.isMatch)(dateString, ISO9075_DATETIME_FORMAT) || (0, _datefns.isMatch)(dateString, ISO9075_DATE_FORMAT);
const isISO9075DateString = (dateString)=>(0, _datefns.isMatch)(dateString, ISO9075_DATE_FORMAT);
const trimToDate = (date)=>date?.slice(0, 10);
const trimToTime = (date)=>{
    const time = date?.slice(11, 19);
    return time?.length === 5 ? `${time}:00` : time;
};
const makeDateObject = (date)=>{
    if (typeof date !== 'string') return date;
    return isISOString(date) ? (0, _datefns.parseISO)(date) : new Date(date.replace(' ', 'T'));
};
const parseDate = (date)=>{
    if (date == null) return null;
    if (typeof date === 'string' && date.trim() === '') return null;
    const dateObj = makeDateObject(date);
    if (!(0, _datefns.isValid)(dateObj)) throw new Error('Not a valid date');
    return dateObj;
};
const toDateTimeString = (date)=>{
    const parsed = parseDate(date);
    return parsed ? (0, _datefns.formatISO9075)(parsed, {
        representation: 'complete'
    }) : null;
};
const toDateString = (date)=>{
    const parsed = parseDate(date);
    return parsed ? (0, _datefns.formatISO9075)(parsed, {
        representation: 'date'
    }) : null;
};
const toWeekdayCode = (date)=>{
    const parsed = parseDate(date);
    return parsed ? (0, _datefns.format)(parsed, 'iiiiii').toUpperCase() : null;
};
const getCurrentDateString = ()=>(0, _datefns.formatISO9075)(new Date(), {
        representation: 'date'
    });
const getCurrentDateTimeString = ()=>(0, _datefns.formatISO9075)(new Date());
const getDateTimeSubtractedFromNow = (daysToSubtract)=>toDateTimeString((0, _datefns.sub)(new Date(), {
        days: daysToSubtract
    }));
const getCurrentISO8601DateString = ()=>new Date().toISOString();
const convertISO9075toRFC3339 = (dateString)=>{
    const parsedDate = dateString == null ? new Date() : (0, _datefns.parseISO)(dateString);
    return (0, _datefns.format)(parsedDate, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
};
const ageIn = (diffFn)=>(dob)=>diffFn(new Date(), (0, _datefns.parseISO)(dob));
const ageInWeeks = ageIn(_datefns.differenceInWeeks);
const ageInMonths = ageIn(_datefns.differenceInMonths);
const ageInYears = ageIn(_datefns.differenceInYears);
const getAgeRangeInMinutes = ({ ageMin = -Infinity, ageMax = Infinity, ageUnit })=>{
    const timeUnit = _constants.TIME_UNIT_OPTIONS.find((option)=>option.unit === ageUnit);
    if (!timeUnit) return null;
    const conversionValue = timeUnit.minutes;
    return {
        ageMin: ageMin * conversionValue,
        ageMax: ageMax * conversionValue,
        previousAgeUnit: ageUnit
    };
};
const doAgeRangesHaveGaps = (rangesArray)=>{
    const conversions = {
        weeks: {
            months: (a, b)=>{
                const weeks = a.ageMax / 60 / 24 / 7;
                const months = b.ageMin / 60 / 24 / 30;
                return weeks / 4 !== months;
            },
            years: (a, b)=>{
                const weeks = a.ageMax / 60 / 24 / 7;
                const years = b.ageMin / 60 / 24 / 365;
                return weeks / 52 !== years;
            }
        },
        months: {
            years: (a, b)=>{
                const months = a.ageMax / 60 / 24 / 30;
                const years = b.ageMin / 60 / 24 / 365;
                return months / 12 !== years;
            }
        }
    };
    // Get all values into same time unit and sort by ageMin low to high
    const normalized = rangesArray.map(getAgeRangeInMinutes).filter((range)=>range !== null);
    normalized.sort((a, b)=>a.ageMin - b.ageMin);
    return normalized.some((rangeA, i)=>{
        const rangeB = normalized[i + 1];
        if (!rangeB) return false;
        if (rangeA.previousAgeUnit !== rangeB.previousAgeUnit) {
            // Cross-unit boundary — minute comparison may not be reliable, use explicit conversion
            const conversion = conversions[rangeA.previousAgeUnit]?.[rangeB.previousAgeUnit];
            if (conversion) return conversion(rangeA, rangeB);
        }
        return rangeA.ageMax !== rangeB.ageMin;
    });
};
const doAgeRangesOverlap = (rangesArray)=>rangesArray.some((rangeA, aIndex)=>rangesArray.some((rangeB, bIndex)=>{
            if (aIndex >= bIndex) return false;
            const a = getAgeRangeInMinutes(rangeA);
            const b = getAgeRangeInMinutes(rangeB);
            if (!a || !b) return false;
            // Min inclusive, max exclusive — standard half-open interval overlap check
            return a.ageMin < b.ageMax && b.ageMin < a.ageMax;
        }));
const format = (date, formatStr)=>{
    const parsed = parseDate(date);
    return parsed ? (0, _datefns.format)(parsed, formatStr) : null;
};
const differenceInMilliseconds = (a, b)=>(0, _datefns.differenceInMilliseconds)(new Date(a), new Date(b));
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
const isStartOfThisWeek = (date)=>(0, _datefns.isSameDay)(date, (0, _datefns.startOfWeek)(new Date(), {
        weekStartsOn: 1
    }));
const endpointsOfDay = (date)=>[
        (0, _datefns.startOfDay)(date),
        (0, _datefns.endOfDay)(date)
    ];
const isIntervalWithinInterval = (interval1, interval2)=>{
    const { start, end } = interval1;
    return (0, _datefns.isWithinInterval)(start, interval2) && (0, _datefns.isWithinInterval)(end, interval2);
};
const isWithinIntervalExcludingEnd = (date, interval)=>(0, _datefns.isBefore)(date, interval.end) && (0, _datefns.isWithinInterval)(date, interval);
const boundValidDate = (fn)=>(dates)=>{
        const validDates = dates.filter(_datefns.isValid);
        return validDates.length === 0 ? null : fn(validDates);
    };
const maxValidDate = boundValidDate(_datefns.max);
const minValidDate = boundValidDate(_datefns.min);
const eachDayInMonth = (date)=>(0, _datefns.eachDayOfInterval)({
        start: (0, _datefns.startOfMonth)(date),
        end: (0, _datefns.endOfMonth)(date)
    });
const iso9075Validator = (regex, message)=>_zod.z.string().refine((val)=>regex.test(val) && (0, _datefns.isValid)((0, _datefns.parseISO)(val.replace(' ', 'T'))), {
        message
    });
const dateCustomValidation = iso9075Validator(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format, expected YYYY-MM-DD').describe('__dateCustomValidation__');
const PLAIN_TIME_PATTERN = /^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/;
const timeCustomValidation = _zod.z.string().refine((val)=>PLAIN_TIME_PATTERN.test(val), {
    message: 'Invalid time format, expected HH:MM:SS'
});
const datetimeCustomValidation = iso9075Validator(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/, 'Invalid datetime format, expected YYYY-MM-DD HH:MM:SS').describe('__datetimeCustomValidation__');
const pad = (n)=>String(n).padStart(2, '0');
const formatTemporal = (dt, separator, alwaysIncludeSeconds)=>{
    const { year, month, day, hour, minute, second } = dt;
    const yyyy = String(year).padStart(4, '0');
    const base = `${yyyy}-${pad(month)}-${pad(day)}${separator}${pad(hour)}:${pad(minute)}`;
    return alwaysIncludeSeconds || second !== 0 ? `${base}:${pad(second)}` : base;
};
const toISO9075DateTime = (dt)=>formatTemporal(dt, ' ', true);
const toDateTimeLocalFormat = (dt)=>formatTemporal(dt, 'T', false);
const parseDateTimeString = (date, primaryTimeZone)=>{
    const normalized = date.replace(' ', 'T');
    if (/[Zz]$/.test(normalized)) {
        const instant = _temporalpolyfill.Temporal.Instant.from(normalized);
        const tz = primaryTimeZone ?? _temporalpolyfill.Temporal.Now.timeZoneId();
        return instant.toZonedDateTimeISO(tz).toPlainDateTime();
    }
    return _temporalpolyfill.Temporal.PlainDateTime.from(normalized);
};
const getDisplayTimezone = (primaryTimeZone, facilityTimeZone)=>facilityTimeZone ?? primaryTimeZone;
const isTimezoneError = (error)=>error instanceof RangeError && /time\s*zone/i.test(String(error));
const logDateError = (fnName, error, value, primaryTimeZone, facilityTimeZone)=>{
    if (isTimezoneError(error)) {
        console.error(`[${fnName}] Invalid timezone configuration — primaryTimeZone: ${JSON.stringify(primaryTimeZone)}, facilityTimeZone: ${JSON.stringify(facilityTimeZone)}. Error:`, error);
    } else {
        console.warn(`[${fnName}] Failed to process date value ${JSON.stringify(value)}:`, error);
    }
};
const intlFormatDate = (date, formatOptions, fallback = 'Unknown', primaryTimeZone, facilityTimeZone, localeOverride)=>{
    if (!date) return fallback;
    const displayLocale = localeOverride ?? locale;
    try {
        if (date instanceof Date) {
            if (!(0, _datefns.isValid)(date)) return fallback;
            return date.toLocaleString(displayLocale, formatOptions);
        }
        if (isISO9075DateString(date)) {
            const plainDate = _temporalpolyfill.Temporal.PlainDate.from(date);
            const timeKeys = [
                'hour',
                'minute',
                'second',
                'timeStyle',
                'dayPeriod'
            ];
            const hasTimeOptions = timeKeys.some((key)=>key in formatOptions);
            if (hasTimeOptions) {
                return plainDate.toPlainDateTime().toLocaleString(displayLocale, formatOptions);
            }
            return plainDate.toLocaleString(displayLocale, formatOptions);
        }
        const displayTz = getDisplayTimezone(primaryTimeZone, facilityTimeZone);
        const plain = parseDateTimeString(date, primaryTimeZone);
        if (primaryTimeZone && displayTz) {
            return plain.toZonedDateTime(primaryTimeZone).withTimeZone(displayTz).toLocaleString(displayLocale, formatOptions);
        }
        return plain.toLocaleString(displayLocale, formatOptions);
    } catch (error) {
        logDateError('intlFormatDate', error, date, primaryTimeZone, facilityTimeZone);
        return fallback;
    }
};
const getCurrentDateTimeStringInTimezone = (timezone)=>toISO9075DateTime(_temporalpolyfill.Temporal.Now.zonedDateTimeISO(timezone ?? _temporalpolyfill.Temporal.Now.timeZoneId()));
const getCurrentDateStringInTimezone = (timezone)=>_temporalpolyfill.Temporal.Now.plainDateISO(timezone ?? _temporalpolyfill.Temporal.Now.timeZoneId()).toString();
const storedDateTimeToEpochMilliseconds = (storedValue, primaryTimeZone)=>{
    if (storedValue == null || typeof storedValue === 'string' && storedValue.trim() === '') {
        return null;
    }
    try {
        const normalized = storedValue.replace(' ', 'T');
        if (/[Zz]$/.test(normalized)) {
            return _temporalpolyfill.Temporal.Instant.from(normalized).epochMilliseconds;
        }
        const plain = _temporalpolyfill.Temporal.PlainDateTime.from(normalized);
        return plain.toZonedDateTime(primaryTimeZone).epochMilliseconds;
    } catch  {
        return null;
    }
};
const getFacilityNowDate = (primaryTimeZone, facilityTimeZone)=>{
    const tz = facilityTimeZone ?? primaryTimeZone;
    return new Date(getCurrentDateTimeStringInTimezone(tz).replace(' ', 'T'));
};
const toFacilityDateTime = (value, primaryTimeZone, facilityTimeZone)=>{
    if (value == null) return null;
    try {
        const displayTz = getDisplayTimezone(primaryTimeZone, facilityTimeZone);
        if (value instanceof Date) {
            if (!(0, _datefns.isValid)(value)) return null;
            const instant = _temporalpolyfill.Temporal.Instant.fromEpochMilliseconds(value.getTime());
            return toDateTimeLocalFormat(instant.toZonedDateTimeISO(displayTz ?? _temporalpolyfill.Temporal.Now.timeZoneId()));
        }
        if (isISO9075DateString(value)) {
            // Omit seconds to match toDateTimeLocalFormat and HTML datetime-local input values
            return `${value}T00:00`;
        }
        const plain = parseDateTimeString(value, primaryTimeZone);
        if (primaryTimeZone && displayTz) {
            return toDateTimeLocalFormat(plain.toZonedDateTime(primaryTimeZone).withTimeZone(displayTz));
        }
        return toDateTimeLocalFormat(plain);
    } catch (error) {
        logDateError('toFacilityDateTime', error, value, primaryTimeZone, facilityTimeZone);
        return null;
    }
};
const toStoredDateTime = (inputValue, primaryTimeZone, facilityTimeZone)=>{
    if (!inputValue) return null;
    try {
        if (/[Zz]$/.test(inputValue)) {
            const instant = _temporalpolyfill.Temporal.Instant.from(inputValue.replace(' ', 'T'));
            const tz = primaryTimeZone ?? _temporalpolyfill.Temporal.Now.timeZoneId();
            return toISO9075DateTime(instant.toZonedDateTimeISO(tz));
        }
        const plain = parseDateTimeString(inputValue, primaryTimeZone);
        if (!primaryTimeZone) {
            return toISO9075DateTime(plain);
        }
        const inputTz = getDisplayTimezone(primaryTimeZone, facilityTimeZone);
        return toISO9075DateTime(plain.toZonedDateTime(inputTz).withTimeZone(primaryTimeZone));
    } catch (error) {
        logDateError('toStoredDateTime', error, inputValue, primaryTimeZone, facilityTimeZone);
        return null;
    }
};
const getDayBoundaries = (date, primaryTimeZone, facilityTimeZone)=>{
    const start = toStoredDateTime(`${date}T00:00:00`, primaryTimeZone, facilityTimeZone);
    const end = toStoredDateTime(`${date}T23:59:59`, primaryTimeZone, facilityTimeZone);
    if (!start || !end) return null;
    return {
        start,
        end
    };
};
function isValidSurveyTimeBody(value) {
    if (value == null) return false;
    const s = value.trim();
    if (s === '') return false;
    return PLAIN_TIME_PATTERN.test(s);
}
function parseSurveyTimeToHHmmss(input) {
    const trimmed = input?.trim();
    if (!trimmed) return null;
    if (PLAIN_TIME_PATTERN.test(trimmed)) return trimmed;
    const hhmm = /^([01]\d|2[0-3]):([0-5]\d)$/;
    const match = trimmed.match(hhmm);
    if (match) {
        const [, hour, minute] = match;
        return `${hour}:${minute}:00`;
    }
    return null;
}
function formatSurveyTimeFromDate(date) {
    if (!(0, _datefns.isValid)(date)) return null;
    return (0, _datefns.format)(date, 'HH:mm:ss');
}

//# sourceMappingURL=dateTime.js.map