"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUserTimzoneDate = exports.getMinutesFromDate = exports.toDate = exports.roundHours = exports.getUtcWeekStartEndFromDate = exports.getUtcDateRange = exports.getUtcStartEndOfDate = exports.getUtcMonthStartEndFromDate = exports.getUtcMonthStartEnd = exports.getMonthUtcRange = exports.uniqueUserid = exports.getPurchaseType = exports.isEmptyObj = exports.filterUndefined = exports.getOtp = exports.getUnixTime = exports.formatBreakDuration = exports.presentExceptionStatuses = exports.attendancePastPresentStatuses = exports.attendancePresentStatuses = exports.TIME_ZONE = exports.DHAKA_OFFSET = void 0;
exports.getStartEndOfDay = getStartEndOfDay;
exports.getStartEndOfDate = getStartEndOfDate;
exports.getDateDuration = getDateDuration;
const date_fns_1 = require("date-fns");
const date_fns_tz_1 = require("date-fns-tz");
const getHours_1 = require("date-fns/getHours");
const getMinutes_1 = require("date-fns/getMinutes");
const isValid_1 = require("date-fns/isValid");
const parseISO_1 = require("date-fns/parseISO");
const zod_1 = require("zod");
const timezone_constants_1 = require("../common/timezone/timezone.constants");
const config_1 = require("../config");
exports.DHAKA_OFFSET = 6 * 60 * 60 * 1000;
exports.TIME_ZONE = timezone_constants_1.DEFAULT_ORG_TIMEZONE;
exports.attendancePresentStatuses = [
    'present',
    'remote',
    'half_day',
    'late',
    'on_break',
    'check_in',
];
exports.attendancePastPresentStatuses = [
    'present',
    'remote',
    'half_day',
    'late',
];
exports.presentExceptionStatuses = [
    'check_in',
    'on_break',
    'late',
    'remote',
    'half_day',
];
const formatBreakDuration = (minutes) => {
    if (!minutes || minutes <= 0) {
        return '0 minutes';
    }
    const hours = Math.floor(minutes / 60);
    const mins = Math.floor(minutes % 60);
    let result = '';
    if (hours > 0) {
        result += `${hours} hour${hours !== 1 ? 's' : ''}`;
    }
    if (mins > 0) {
        if (result.length > 0)
            result += ' ';
        result += `${mins} minute${mins !== 1 ? 's' : ''}`;
    }
    if (result.length === 0) {
        return '0 minutes';
    }
    return result;
};
exports.formatBreakDuration = formatBreakDuration;
const getUnixTime = (type = 's', extraTime = 0) => {
    const time = Date.now();
    const extraMilliseconds = extraTime * 60 * 1000;
    const convertedTime = type === 'ms'
        ? Math.floor((time + extraMilliseconds) / 1000)
        : time + extraMilliseconds;
    return convertedTime;
};
exports.getUnixTime = getUnixTime;
const getOtp = (digits = 6) => {
    const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let otp = '';
    for (let i = 0; i < digits; i++) {
        otp += chars[Math.floor(Math.random() * chars.length)];
    }
    return otp;
};
exports.getOtp = getOtp;
const filterUndefined = (obj) => {
    return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value !== undefined && value !== null && value !== ''));
};
exports.filterUndefined = filterUndefined;
const isEmptyObj = (obj) => {
    return Object.entries(obj).length === 0;
};
exports.isEmptyObj = isEmptyObj;
const getPurchaseType = (amount = 0, totalAmount = 0) => {
    if (amount === 0) {
        return config_1.PurchaseType.fullPay;
    }
    else if (amount > 0) {
        return config_1.PurchaseType.partial;
    }
    else if (amount > totalAmount) {
        return config_1.PurchaseType.extraPay;
    }
    else {
        return config_1.PurchaseType.duePay;
    }
};
exports.getPurchaseType = getPurchaseType;
const uniqueUserid = (name) => {
    if (!name)
        return (0, zod_1.uuidv4)();
    const namePart = name
        .split(' ')
        .map((part) => part.slice(0, 2).toUpperCase())
        .join('_');
    const timestampPart = Date.now().toString().slice(-3);
    const randomPart = Math.random().toString(36).slice(2, 4).toUpperCase();
    return `${namePart}${timestampPart}${randomPart}`;
};
exports.uniqueUserid = uniqueUserid;
function getStartEndOfDay(offsetHours) {
    const now = new Date();
    const utc = now.getTime() + now.getTimezoneOffset() * 60000;
    const local = new Date(utc + offsetHours * 3600000);
    const start = new Date(local);
    start.setHours(0, 0, 0, 0);
    const end = new Date(local);
    end.setHours(23, 59, 59, 999);
    return {
        start: new Date(start.getTime() - offsetHours * 3600000),
        end: new Date(end.getTime() - offsetHours * 3600000),
    };
}
function getStartEndOfDate(date, offsetHours) {
    const inputDate = date ? new Date(date) : new Date();
    const shifted = new Date(inputDate.getTime() + offsetHours * 3600000);
    const year = shifted.getUTCFullYear();
    const month = shifted.getUTCMonth();
    const day = shifted.getUTCDate();
    const startUtcMillis = Date.UTC(year, month, day) - offsetHours * 3600000;
    const start = new Date(startUtcMillis);
    const end = new Date(startUtcMillis + 24 * 3600000 - 1);
    return { start, end };
}
const getMonthUtcRange = (input, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const date = input instanceof Date && !isNaN(input.getTime()) ? input : new Date();
    const year = (0, date_fns_tz_1.formatInTimeZone)(date, timeZone, 'yyyy');
    const month = (0, date_fns_tz_1.formatInTimeZone)(date, timeZone, 'MM');
    const startBd = `${year}-${month}-01 00:00:00`;
    const nextMonthDate = new Date(Number(year), Number(month) - 1 + 1, 1);
    const nextYear = (0, date_fns_tz_1.formatInTimeZone)(nextMonthDate, timeZone, 'yyyy');
    const nextMonth = (0, date_fns_tz_1.formatInTimeZone)(nextMonthDate, timeZone, 'MM');
    const nextMonthStartBd = `${nextYear}-${nextMonth}-01 00:00:00`;
    const startUtc = (0, date_fns_tz_1.fromZonedTime)(startBd, timeZone);
    const endUtc = new Date((0, date_fns_tz_1.fromZonedTime)(nextMonthStartBd, timeZone).getTime() - 1);
    return { startUtc, endUtc };
};
exports.getMonthUtcRange = getMonthUtcRange;
const getUtcMonthStartEnd = (year, month, expandedCount = 0, 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);
    const endUtc = new Date(nextMonthStartUtc.getTime() - 1);
    return {
        startUtc: expandedCount > 0
            ? (0, date_fns_1.subMilliseconds)(monthStartUtc, expandedCount)
            : monthStartUtc,
        endUtc: expandedCount > 0 ? (0, date_fns_1.addMilliseconds)(endUtc, expandedCount) : endUtc,
    };
};
exports.getUtcMonthStartEnd = getUtcMonthStartEnd;
const getUtcMonthStartEndFromDate = (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.getUtcMonthStartEnd)(year, month, 0, timeZone);
};
exports.getUtcMonthStartEndFromDate = getUtcMonthStartEndFromDate;
const getUtcStartEndOfDate = (input, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    try {
        let date;
        if (typeof input === 'string') {
            if (/^\d{4}-\d{2}-\d{2}$/.test(input)) {
                date = (0, date_fns_tz_1.fromZonedTime)(`${input} 00:00:00`, timeZone);
            }
            else {
                date = new Date(input);
            }
        }
        else {
            date = input;
        }
        if (isNaN(date.getTime())) {
            date = new Date();
        }
        const localDateStr = (0, date_fns_tz_1.formatInTimeZone)(date, timeZone, 'yyyy-MM-dd');
        const startBd = `${localDateStr} 00:00:00`;
        const endBd = `${localDateStr} 23:59:59.999`;
        return {
            startUtc: (0, date_fns_tz_1.fromZonedTime)(startBd, timeZone),
            endUtc: (0, date_fns_tz_1.fromZonedTime)(endBd, timeZone),
        };
    }
    catch (error) {
        console.error('Error in getUtcStartEndOfDate:', error);
        const fallbackDate = new Date();
        const localDateStr = (0, date_fns_tz_1.formatInTimeZone)(fallbackDate, timeZone, 'yyyy-MM-dd');
        return {
            startUtc: (0, date_fns_tz_1.fromZonedTime)(`${localDateStr} 00:00:00`, timeZone),
            endUtc: (0, date_fns_tz_1.fromZonedTime)(`${localDateStr} 23:59:59.999`, timeZone),
        };
    }
};
exports.getUtcStartEndOfDate = getUtcStartEndOfDate;
const getUtcDateRange = (start, end, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const startDate = (0, exports.toDate)(start) ?? new Date();
    const endDate = (0, exports.toDate)(end) ?? new Date();
    const startBd = (0, date_fns_tz_1.formatInTimeZone)(startDate, timeZone, 'yyyy-MM-dd');
    const endBd = (0, date_fns_tz_1.formatInTimeZone)(endDate, timeZone, 'yyyy-MM-dd');
    return {
        startUtc: (0, date_fns_tz_1.fromZonedTime)(`${startBd} 00:00:00`, timeZone),
        endUtc: (0, date_fns_tz_1.fromZonedTime)(`${endBd} 23:59:59`, timeZone),
    };
};
exports.getUtcDateRange = getUtcDateRange;
const getUtcWeekStartEndFromDate = (date, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const normalizedDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : new Date();
    const localDateStr = (0, date_fns_tz_1.formatInTimeZone)(normalizedDate, timeZone, 'yyyy-MM-dd');
    const localDate = (0, parseISO_1.parseISO)(localDateStr);
    const day = localDate.getDay();
    const diffToSaturday = (day + 1) % 7;
    const weekStart = new Date(localDate);
    weekStart.setDate(localDate.getDate() - diffToSaturday);
    weekStart.setHours(0, 0, 0, 0);
    const weekEnd = new Date(weekStart);
    weekEnd.setDate(weekStart.getDate() + 7);
    const startUtc = (0, date_fns_tz_1.fromZonedTime)(weekStart, timeZone);
    const endUtc = new Date((0, date_fns_tz_1.fromZonedTime)(weekEnd, timeZone).getTime() - 1);
    return {
        startUtc,
        endUtc,
    };
};
exports.getUtcWeekStartEndFromDate = getUtcWeekStartEndFromDate;
const roundHours = (hours) => {
    return Number(hours.toFixed(2));
};
exports.roundHours = roundHours;
const toDate = (value) => {
    if (!value)
        return null;
    if (value instanceof Date)
        return value;
    if (typeof value === 'string') {
        const parsed = (0, parseISO_1.parseISO)(value);
        if ((0, isValid_1.isValid)(parsed))
            return parsed;
        const alt = new Date(value);
        return (0, isValid_1.isValid)(alt) ? alt : null;
    }
    return null;
};
exports.toDate = toDate;
const getMinutesFromDate = (value, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    const v = (0, exports.toDate)(value);
    const zonedDate = (0, date_fns_tz_1.toZonedTime)(v, timeZone);
    return (0, getHours_1.getHours)(zonedDate) * 60 + (0, getMinutes_1.getMinutes)(zonedDate);
};
exports.getMinutesFromDate = getMinutesFromDate;
function getDateDuration(start, end) {
    if (!start || !end)
        return 0;
    const days = (0, date_fns_1.differenceInCalendarDays)(new Date(start), new Date(end)) + 1;
    return Math.max(0, days);
}
const getUserTimzoneDate = (date, timeZone = timezone_constants_1.DEFAULT_ORG_TIMEZONE) => {
    return (0, date_fns_tz_1.formatInTimeZone)(date, timeZone, 'dd MMM yyyy');
};
exports.getUserTimzoneDate = getUserTimzoneDate;
//# sourceMappingURL=helpers.js.map