"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DashboardService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("typeorm");
const permission_resolver_helpers_1 = require("../../common/access-control/permission-resolver.helpers");
const permission_resolver_service_1 = require("../../common/access-control/permission-resolver.service");
const org_timezone_service_1 = require("../../common/timezone/org-timezone.service");
const config_1 = require("../../config");
const utils_1 = require("../../utils");
const dashboard_1 = require("../../utils/dashboard");
const leaves_dto_1 = require("../leaves/leaves.dto");
let DashboardService = class DashboardService {
    constructor(db, permissionResolver, orgTimezone) {
        this.db = db;
        this.permissionResolver = permissionResolver;
        this.orgTimezone = orgTimezone;
    }
    async getPermissions(ctx) {
        return this.permissionResolver.resolveForUser(ctx);
    }
    async getThisWeeks(owner_id, ctx, dataScope) {
        try {
            const timeZone = await this.orgTimezone.getTimezone(owner_id);
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'dashboard.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'dashboard.view', dataScope, ctx);
            const isOwnData = scopeFilter === 'own';
            const member_id = ctx.sub;
            const today = new Date();
            const { startUtc, endUtc } = (0, utils_1.getUtcStartEndOfDate)(today, timeZone);
            const { startUtc: weekStartUtc, endUtc: weekEndUtc } = (0, utils_1.getUtcWeekStartEndFromDate)(today, timeZone);
            const calculationEndUtc = endUtc < weekEndUtc ? endUtc : weekEndUtc;
            const member = isOwnData
                ? await this.db.members.findUnique({
                    where: { id: member_id, owner_id },
                    select: { department_id: true },
                })
                : null;
            const totalMembers = isOwnData
                ? 1
                : await this.db.members.count({
                    where: { owner_id, status: 'active' },
                });
            const nonRecurringHolidayWhere = {
                owner_id,
                is_recurring: false,
                start_date: (0, typeorm_1.LessThanOrEqual)(calculationEndUtc),
                end_date: (0, typeorm_1.MoreThanOrEqual)(weekStartUtc),
            };
            const recurringHolidayWhere = {
                owner_id,
                is_recurring: true,
            };
            if (isOwnData && member?.department_id) {
                recurringHolidayWhere.departments = {
                    some: {
                        id: member.department_id,
                    },
                };
                nonRecurringHolidayWhere.departments = {
                    some: {
                        id: member.department_id,
                    },
                };
            }
            const [workSchedule, nonRecurringHolidays, recurringHolidays, attendances, leaves,] = await Promise.all([
                this.db.working_schedule.findFirst({
                    where: { owner_id },
                }),
                this.db.holidays.findMany({
                    where: nonRecurringHolidayWhere,
                    include: {
                        departments: true,
                    },
                }),
                this.db.holidays.findMany({
                    where: recurringHolidayWhere,
                }),
                this.db.attendances.findMany({
                    where: {
                        owner_id,
                        date: (0, typeorm_1.Between)(weekStartUtc, calculationEndUtc),
                        status: (0, typeorm_1.In)([
                            'present',
                            'check_in',
                            'remote',
                            'late',
                            'half_day',
                            'on_break',
                            'on_leave',
                        ]),
                        ...(isOwnData ? { member_id } : {}),
                    },
                    orderBy: {
                        date: 'desc',
                    },
                }),
                this.db.leaves.findMany({
                    where: {
                        owner_id,
                        status: 'approved',
                        start_date: (0, typeorm_1.LessThanOrEqual)(calculationEndUtc),
                        end_date: (0, typeorm_1.MoreThanOrEqual)(weekStartUtc),
                        ...(isOwnData && { member_id: member.id }),
                    },
                }),
            ]);
            const holidays = (0, utils_1.getCurrentMonthHolidays)(recurringHolidays, nonRecurringHolidays, weekStartUtc, weekEndUtc);
            const weekDetails = (0, dashboard_1.getCurrentWeekDetails)(weekStartUtc, weekEndUtc, holidays, leaves, workSchedule);
            const thisWeekLeaveCount = (0, dashboard_1.getLeaveCountFromStartAndEnd)(leaves, workSchedule, weekStartUtc, calculationEndUtc);
            const workingDayCount = (0, dashboard_1.getTotalWorkingDayFromStartAndEnd)(holidays, workSchedule, weekStartUtc, calculationEndUtc);
            const { attendance_count, late_count, half_day_count } = (0, dashboard_1.getAttendanceDetailsCountFromStartAndEnd)(attendances, weekStartUtc, calculationEndUtc, startUtc);
            const absentCount = isOwnData
                ? Math.max(0, workingDayCount -
                    thisWeekLeaveCount -
                    attendance_count -
                    late_count -
                    half_day_count)
                : Math.max(0, workingDayCount * totalMembers -
                    thisWeekLeaveCount -
                    attendance_count -
                    late_count -
                    half_day_count);
            return {
                data: weekDetails,
                details: {
                    present: attendance_count,
                    late: late_count,
                    half_day: half_day_count,
                    absent: absentCount,
                    leave: thisWeekLeaveCount,
                },
                status: common_1.HttpStatus.OK,
                message: 'This week summary fetched successfully',
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getThisWeeks: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getSummary(owner_id, ctx, dataScope) {
        try {
            const timeZone = await this.orgTimezone.getTimezone(owner_id);
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'dashboard.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'dashboard.view', dataScope, ctx);
            const isOwnData = scopeFilter === 'own';
            const member_id = ctx.sub;
            const today = new Date();
            const { startUtc, endUtc } = (0, utils_1.getUtcStartEndOfDate)(today, timeZone);
            const { startUtc: monthStartUtc, endUtc: monthEndUtc } = (0, utils_1.getUtcMonthStartEndFromDate)(today, timeZone);
            const isMember = isOwnData;
            const summaryData = {
                total_members: 0,
                today_status: 'absent',
                present_days: 0,
                leave_days: 0,
                absent_days: 0,
                this_week_leave_days: 0,
                this_week_holidays: 0,
                today_pending_leaves: 0,
                today_absent_count: 0,
                today_leave_count: 0,
                today_present_count: 0,
            };
            if (isMember) {
                const [attendances, leaves, work_schedule] = await Promise.all([
                    this.db.attendances.findMany({
                        where: {
                            member_id,
                            date: (0, typeorm_1.Between)(monthStartUtc, monthEndUtc),
                        },
                    }),
                    this.db.leaves.findMany({
                        where: {
                            member_id,
                            status: 'approved',
                            start_date: (0, typeorm_1.Between)(monthStartUtc, monthEndUtc),
                        },
                    }),
                    this.db.working_schedule.findFirst({
                        where: { owner_id },
                    }),
                ]);
                attendances.forEach((attendance) => {
                    const isToday = attendance.date >= startUtc && attendance.date <= endUtc;
                    if (isToday) {
                        summaryData.today_status = attendance.status;
                    }
                    if ((0, utils_1.isGroupedPresent)(attendance.status, isToday)) {
                        summaryData.present_days += 1;
                    }
                    else if ((0, utils_1.isGroupedAbsent)(attendance.status, isToday)) {
                        summaryData.absent_days += 1;
                    }
                });
                summaryData.leave_days = (0, dashboard_1.getLeaveCountFromStartAndEnd)(leaves, work_schedule, monthStartUtc, monthEndUtc, false);
            }
            else {
                const [memberCount, todayAttendances] = await Promise.all([
                    this.db.members.count({
                        where: { owner_id, status: 'active' },
                    }),
                    this.db.attendances.findMany({
                        where: {
                            owner_id,
                            date: (0, typeorm_1.Between)(startUtc, endUtc),
                        },
                    }),
                ]);
                summaryData.total_members = memberCount;
                todayAttendances.forEach((attendance) => {
                    if ((0, utils_1.isGroupedPresent)(attendance.status, true)) {
                        summaryData.today_present_count += 1;
                    }
                    else if (attendance.status === 'on_leave') {
                        summaryData.today_leave_count += 1;
                    }
                    else if (attendance.status === 'absent') {
                        summaryData.today_absent_count += 1;
                    }
                });
            }
            return {
                data: summaryData,
                details: null,
                status: common_1.HttpStatus.OK,
                message: 'Summary fetched successfully',
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getSummary: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getThisMonthReport(owner_id, ctx, dataScope) {
        try {
            const timeZone = await this.orgTimezone.getTimezone(owner_id);
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'dashboard.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'dashboard.view', dataScope, ctx);
            const isMember = scopeFilter === 'own';
            const member_id = ctx.sub;
            const today = new Date();
            const { startUtc: todayStartUtc } = (0, utils_1.getUtcStartEndOfDate)(today, timeZone);
            const { startUtc, endUtc } = (0, utils_1.getUtcMonthStartEndFromDate)(today, timeZone);
            const member = isMember
                ? await this.db.members.findUnique({
                    where: { id: member_id, owner_id },
                    select: { department_id: true },
                })
                : null;
            const totalMembers = isMember
                ? 1
                : await this.db.members.count({
                    where: { owner_id, status: 'active' },
                });
            const asnDates = (0, typeorm_1.Between)(startUtc, endUtc);
            const nonRecurringHolidayWhere = {
                owner_id,
                is_recurring: false,
                start_date: asnDates,
            };
            const recurringHolidayWhere = {
                owner_id,
                is_recurring: true,
            };
            if (isMember && member?.department_id) {
                recurringHolidayWhere.departments = {
                    some: {
                        id: member.department_id,
                    },
                };
                nonRecurringHolidayWhere.departments = {
                    some: {
                        id: member.department_id,
                    },
                };
            }
            const [workSchedule, nonRecurringHolidays, recurringHolidays, attendances, leaves,] = await Promise.all([
                this.db.working_schedule.findFirst({
                    where: { owner_id },
                }),
                this.db.holidays.findMany({
                    where: nonRecurringHolidayWhere,
                    include: {
                        departments: true,
                    },
                }),
                this.db.holidays.findMany({
                    where: recurringHolidayWhere,
                }),
                this.db.attendances.findMany({
                    where: {
                        owner_id,
                        date: asnDates,
                        status: (0, typeorm_1.In)([
                            'present',
                            'check_in',
                            'remote',
                            'late',
                            'half_day',
                            'on_break',
                            'on_leave',
                        ]),
                        ...(isMember ? { member_id } : {}),
                    },
                    orderBy: {
                        date: 'desc',
                    },
                }),
                this.db.leaves.findMany({
                    where: {
                        owner_id,
                        status: 'approved',
                        start_date: (0, typeorm_1.LessThanOrEqual)(endUtc),
                        end_date: (0, typeorm_1.MoreThanOrEqual)(startUtc),
                        ...(isMember && { member_id: member.id }),
                    },
                }),
            ]);
            const holidays = (0, utils_1.getCurrentMonthHolidays)(recurringHolidays, nonRecurringHolidays, startUtc, endUtc);
            const holidayCount = (0, dashboard_1.countHolidayFromStartAndEnd)(holidays, workSchedule, startUtc, endUtc);
            const thisMonthLeaveCount = (0, dashboard_1.getLeaveCountFromStartAndEnd)(leaves, workSchedule, startUtc, endUtc, false);
            const workingDayCount = (0, dashboard_1.getTotalWorkingDayFromStartAndEnd)(holidays, workSchedule, startUtc, endUtc);
            const attendanceCountInRange = (0, dashboard_1.getAttendanceCountFromStartAndEnd)(attendances, startUtc, endUtc, todayStartUtc);
            const absentCount = isMember
                ? Math.max(0, workingDayCount - thisMonthLeaveCount - attendanceCountInRange)
                : Math.max(0, workingDayCount * totalMembers -
                    thisMonthLeaveCount -
                    attendanceCountInRange);
            const totalPossibleAttendance = workingDayCount * totalMembers;
            const attendancePercentage = totalPossibleAttendance === 0
                ? 0
                : Math.round((attendanceCountInRange / totalPossibleAttendance) * 10000) / 100;
            config_1.logger.error(`attendanceCountInRange: ${workingDayCount}`);
            config_1.logger.error(`attendanceCountInRange: ${holidayCount}`);
            config_1.logger.error(`totalPossibleAttendance: ${totalPossibleAttendance}`);
            config_1.logger.error(`attendancePercentage: ${attendancePercentage}`);
            return {
                data: {
                    attendance_percentage: attendancePercentage,
                    working_days: workingDayCount,
                    present_count: attendanceCountInRange,
                    approved_leaves: thisMonthLeaveCount ?? 0,
                    holidays: holidayCount,
                    total_members: totalMembers,
                    absent_count: absentCount,
                },
                details: null,
                status: common_1.HttpStatus.OK,
                message: 'This month summary fetched successfully',
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getThisMonthReport: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getPendingLeaves(owner_id, ctx, query) {
        try {
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'dashboard.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'dashboard.view', query.data_scope, ctx);
            const memberFilter = (0, permission_resolver_helpers_1.buildMemberFilter)(scopeFilter, ctx.sub);
            const page = query.page || 1;
            const limit = query.limit || 4;
            const skip = (page - 1) * limit;
            const where = {
                owner_id,
                status: 'pending',
                ...memberFilter,
            };
            const leaves = await this.db.leaves.findMany({
                where,
                include: {
                    member: {
                        include: {
                            department: true,
                        },
                    },
                    approver_owner: true,
                    approver_member: true,
                },
                orderBy: { created_at: 'desc' },
                skip,
                take: limit,
            });
            const { data: parsedLeaves } = leaves_dto_1.leavesResponseSchema.safeParse(leaves);
            return {
                data: parsedLeaves,
                message: 'Pending leave requests retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getPendingLeaves: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
};
exports.DashboardService = DashboardService;
exports.DashboardService = DashboardService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.DatabaseService,
        permission_resolver_service_1.PermissionResolverService,
        org_timezone_service_1.OrgTimezoneService])
], DashboardService);
//# sourceMappingURL=dashboard.service.js.map