"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCurrentMonthHolidays = exports.getHolidayUtcMonthStartEndFromDate = exports.getHolidayUtcMonthStartEnd = exports.buildHolidaySummary = exports.buildUpcomingHolidayRecurringDates = exports.buildHolidayWhereFilter = exports.ensureHolidayDepartmentIdsExist = exports.includeHolidayDepartments = exports.buildHolidayRecurringRange = exports.buildHolidayRecurringOccurrence = exports.isHolidayLeapYear = exports.getHolidayRangeLength = exports.normalizeHolidayDate = void 0;
const common_1 = require("@nestjs/common");
const date_fns_1 = require("date-fns");
const date_fns_tz_1 = require("date-fns-tz");
const timezone_constants_1 = require("../common/timezone/timezone.constants");
const error_formatter_1 = require("./error-formatter");
const normalizeHolidayDate = (value, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const year = Number((0, date_fns_tz_1.formatInTimeZone)(value, timeZone, 'yyyy'));
    const month = Number((0, date_fns_tz_1.formatInTimeZone)(value, timeZone, 'M')) - 1;
    const day = Number((0, date_fns_tz_1.formatInTimeZone)(value, timeZone, 'd'));
    return new Date(Date.UTC(year, month, day));
};
exports.normalizeHolidayDate = normalizeHolidayDate;
const getHolidayRangeLength = (startDate, endDate, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    return Math.max(0, Math.round(((0, exports.normalizeHolidayDate)(endDate, timeZone).getTime() -
        (0, exports.normalizeHolidayDate)(startDate, timeZone).getTime()) /
        (1000 * 60 * 60 * 24)));
};
exports.getHolidayRangeLength = getHolidayRangeLength;
const isHolidayLeapYear = (year) => {
    return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0);
};
exports.isHolidayLeapYear = isHolidayLeapYear;
const buildHolidayRecurringOccurrence = (baseDate, year, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const month = Number((0, date_fns_tz_1.formatInTimeZone)(baseDate, timeZone, 'M')) - 1;
    const day = Number((0, date_fns_tz_1.formatInTimeZone)(baseDate, timeZone, 'd'));
    if (month === 1 && day === 29 && !(0, exports.isHolidayLeapYear)(year)) {
        return null;
    }
    const occurrence = (0, date_fns_tz_1.fromZonedTime)(`${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')} 00:00:00`, timeZone);
    if (Number((0, date_fns_tz_1.formatInTimeZone)(occurrence, timeZone, 'M')) - 1 !== month ||
        Number((0, date_fns_tz_1.formatInTimeZone)(occurrence, timeZone, 'd')) !== day) {
        return null;
    }
    return occurrence;
};
exports.buildHolidayRecurringOccurrence = buildHolidayRecurringOccurrence;
const buildHolidayRecurringRange = (startDate, endDate, year, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const occurrenceStart = (0, exports.buildHolidayRecurringOccurrence)(startDate, year, timeZone);
    if (!occurrenceStart) {
        return null;
    }
    const occurrenceEnd = new Date(endDate);
    occurrenceEnd.setFullYear(year);
    return { occurrenceStart, occurrenceEnd };
};
exports.buildHolidayRecurringRange = buildHolidayRecurringRange;
const includeHolidayDepartments = () => ({
    departments: true,
});
exports.includeHolidayDepartments = includeHolidayDepartments;
const ensureHolidayDepartmentIdsExist = async (db, departmentIds, owner_id) => {
    if (departmentIds.length === 0) {
        return;
    }
    const existingCount = await db.departments.count({
        where: {
            owner_id,
            id: {
                in: departmentIds,
            },
        },
    });
    if (existingCount !== departmentIds.length) {
        throw (0, error_formatter_1.createGeneralError)('One or more departments are invalid', 'department_ids', common_1.HttpStatus.BAD_REQUEST);
    }
};
exports.ensureHolidayDepartmentIdsExist = ensureHolidayDepartmentIdsExist;
const buildHolidayWhereFilter = (query) => {
    const where = {};
    if (query.holiday_type) {
        where.holiday_type = query.holiday_type;
    }
    if (query.search) {
        where.name = {
            contains: query.search,
        };
    }
    if (typeof query.is_recurring === 'boolean') {
        where.is_recurring = query.is_recurring;
    }
    return where;
};
exports.buildHolidayWhereFilter = buildHolidayWhereFilter;
const buildUpcomingHolidayRecurringDates = (baseDate, count, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const dates = [];
    const now = (0, date_fns_1.startOfDay)(new Date());
    const currentYear = Number((0, date_fns_tz_1.formatInTimeZone)(now, timeZone, 'yyyy'));
    const baseYear = Number((0, date_fns_tz_1.formatInTimeZone)(baseDate, timeZone, 'yyyy'));
    let year = Math.max(currentYear, baseYear);
    while (dates.length < count) {
        const occurrence = (0, exports.buildHolidayRecurringOccurrence)(baseDate, year, timeZone);
        if (occurrence && occurrence >= now) {
            dates.push(occurrence.toISOString());
        }
        year += 1;
    }
    return dates;
};
exports.buildUpcomingHolidayRecurringDates = buildUpcomingHolidayRecurringDates;
const buildHolidaySummary = (rows) => {
    return rows.reduce((acc, item) => {
        if (item.is_recurring) {
            acc.recurring_holidays += 1;
        }
        if (item.holiday_type === 'public') {
            acc.total_national_holidays += 1;
        }
        if (item.holiday_type === 'company') {
            acc.total_company_holidays += 1;
        }
        return acc;
    }, {
        total_holidays: rows.length,
        recurring_holidays: 0,
        total_national_holidays: 0,
        total_company_holidays: 0,
    });
};
exports.buildHolidaySummary = buildHolidaySummary;
const getHolidayUtcMonthStartEnd = (year, month, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const localDate = `${year}-${String(month).padStart(2, '0')}-01 00:00:00`;
    const nextMonth = month === 12 ? 1 : month + 1;
    const nextYear = month === 12 ? year + 1 : year;
    const nextMonthStart = `${nextYear}-${String(nextMonth).padStart(2, '0')}-01 00:00:00`;
    const monthStartUtc = (0, date_fns_tz_1.fromZonedTime)(localDate, timeZone);
    const nextMonthStartUtc = (0, date_fns_tz_1.fromZonedTime)(nextMonthStart, timeZone);
    return {
        startUtc: monthStartUtc,
        endUtc: new Date(nextMonthStartUtc.getTime() - 1),
    };
};
exports.getHolidayUtcMonthStartEnd = getHolidayUtcMonthStartEnd;
const getHolidayUtcMonthStartEndFromDate = (date, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const normalizedDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : new Date();
    const year = Number((0, date_fns_tz_1.formatInTimeZone)(normalizedDate, timeZone, 'yyyy'));
    const month = Number((0, date_fns_tz_1.formatInTimeZone)(normalizedDate, timeZone, 'M'));
    return (0, exports.getHolidayUtcMonthStartEnd)(year, month, timeZone);
};
exports.getHolidayUtcMonthStartEndFromDate = getHolidayUtcMonthStartEndFromDate;
const getCurrentMonthHolidays = (recurringHolidays, nonRecurringHolidays, startUtc, endUtc, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const holidays = [];
    for (const holiday of recurringHolidays) {
        const year = Number((0, date_fns_tz_1.formatInTimeZone)(startUtc, timeZone, 'yyyy'));
        const occurrence = (0, exports.buildHolidayRecurringOccurrence)(new Date(holiday.start_date), year, timeZone);
        if (occurrence && occurrence >= startUtc && occurrence <= endUtc) {
            const occurrenceEnd = new Date(holiday?.end_date);
            occurrenceEnd.setFullYear(year);
            holidays.push({
                ...holiday,
                start_date: occurrence.toISOString(),
                end_date: occurrenceEnd.toISOString(),
            });
        }
    }
    return [...holidays, ...nonRecurringHolidays];
};
exports.getCurrentMonthHolidays = getCurrentMonthHolidays;
//# sourceMappingURL=holiday.js.map