"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.ConfigurationsService = void 0;
const common_1 = require("@nestjs/common");
const org_timezone_service_1 = require("../../common/timezone/org-timezone.service");
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 config_1 = require("../../config");
const utils_1 = require("../../utils");
const configurations_dto_1 = require("./configurations.dto");
let ConfigurationsService = class ConfigurationsService {
    constructor(db, uploadService, permissionResolver, orgTimezone) {
        this.db = db;
        this.uploadService = uploadService;
        this.permissionResolver = permissionResolver;
        this.orgTimezone = orgTimezone;
    }
    async assertSettingsAccess(ctx, manage = false) {
        const permissions = await this.permissionResolver.resolveForUser(ctx);
        (0, permission_resolver_helpers_1.assertSettingsModuleAccess)(permissions, manage);
    }
    async createDefaultConfiguration(owner_id) {
        const { profile } = (0, config_1.envConfig)().server;
        await Promise.all([
            this.db.working_schedule.create({
                data: {
                    working_days: [
                        'saturday',
                        'sunday',
                        'monday',
                        'tuesday',
                        'wednesday',
                        'thursday',
                    ],
                    working_days_per_week: 6,
                    working_hours_per_day: 8,
                    timezone: 'Asia/Dhaka',
                    monthly_correction_limit: 2,
                    owner_id,
                },
            }),
            this.db.leave_policy.create({
                data: {
                    annual_leave_days: 10,
                    sick_leave_days: 10,
                    owner_id,
                },
            }),
            this.db.company.create({
                data: {
                    name: 'NT/APL',
                    company_code: 'NT/APL',
                    email: 'NT/APL',
                    phone: 'NT/APL',
                    address: 'NT/APL',
                    website: 'NT/APL',
                    logo: {
                        file_name: profile,
                        original_name: 'profile.webp',
                        file_size: 8192,
                        mime_type: 'image/webp',
                    },
                    description: 'NT/APL',
                    founded_at: new Date(),
                    industry: 'NT/APL',
                    owner_id,
                },
            }),
        ]);
    }
    async getCompanyInfo(owner_id, ctx) {
        try {
            await this.assertSettingsAccess(ctx);
            const company = await this.db.company.findFirst({ where: { owner_id } });
            if (!company) {
                throw (0, utils_1.createGeneralError)('Company information not found', 'company', common_1.HttpStatus.NOT_FOUND);
            }
            const parsedResult = configurations_dto_1.companyInfoResponseSchema.safeParse(company);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'root', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            return {
                data: parsedData,
                message: 'Company information retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getCompanyInfo: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getWorkSchedule(owner_id, ctx) {
        try {
            const schedule = await this.db.working_schedule.findFirst({
                where: { owner_id },
            });
            if (!schedule) {
                throw (0, utils_1.createGeneralError)('Work schedule not found', 'working_schedule', common_1.HttpStatus.NOT_FOUND);
            }
            const parsedResult = configurations_dto_1.workScheduleResponseSchema.safeParse(schedule);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'working_schedule', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            return {
                data: parsedData,
                message: 'Work schedule retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getWorkSchedule: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getLeavePolicy(owner_id, ctx) {
        try {
            await this.assertSettingsAccess(ctx);
            const schedule = await this.db.leave_policy.findFirst({
                where: { owner_id },
            });
            if (!schedule) {
                throw (0, utils_1.createGeneralError)('Leave policy not found', 'leave_policy', common_1.HttpStatus.NOT_FOUND);
            }
            const parsedResult = configurations_dto_1.leavePolicyResponseSchema.safeParse(schedule);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'leave_policy', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            return {
                data: parsedData,
                message: 'Leave policy retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getLeavePolicy: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateCompanyInfo(id, owner_id, data, ctx) {
        try {
            await this.assertSettingsAccess(ctx, true);
            const company = await this.db.company.findFirst({
                where: { id, owner_id },
            });
            if (!company) {
                throw (0, utils_1.createGeneralError)('Company information not found', 'root', common_1.HttpStatus.NOT_FOUND);
            }
            const { profile } = (0, config_1.envConfig)().server;
            const shouldClearImage = data?.logo === null;
            let image = data?.logo;
            if (image) {
                image = await this.uploadService.moveImage(image, 'company');
            }
            if (shouldClearImage &&
                company.logo &&
                typeof company.logo === 'object' &&
                !Array.isArray(company.logo) &&
                'file_name' in company.logo &&
                'original_name' in company.logo &&
                'file_size' in company.logo &&
                'mime_type' in company.logo) {
                await this.uploadService.removeImage(company.logo);
            }
            const updatedCompany = await this.db.company.update({
                where: { id },
                data: {
                    ...data,
                    logo: image ?? {
                        file_name: profile,
                        original_name: 'profile.webp',
                        file_size: 8192,
                        mime_type: 'image/webp',
                    },
                },
            });
            const parsedResult = configurations_dto_1.companyInfoResponseSchema.safeParse(updatedCompany);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'company', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            return {
                data: parsedData,
                message: 'Company information updated successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateCompanyInfo: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateWorkSchedule(id, owner_id, data, ctx) {
        try {
            await this.assertSettingsAccess(ctx, true);
            const schedule = await this.db.working_schedule.findFirst({
                where: { id, owner_id },
            });
            if (!schedule) {
                throw (0, utils_1.createGeneralError)('Work schedule not found', 'root', common_1.HttpStatus.NOT_FOUND);
            }
            const updatedSchedule = await this.db.working_schedule.update({
                where: { id },
                data: {
                    ...data,
                },
            });
            const parsedResult = configurations_dto_1.workScheduleResponseSchema.safeParse(updatedSchedule);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'working_schedule', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            config_1.logger.info(`Work schedule updated successfully: ${JSON.stringify(parsedData)}`);
            this.orgTimezone.invalidate(owner_id);
            return {
                data: parsedData,
                message: 'Work schedule updated successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateWorkSchedule: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateLeavePolicy(id, owner_id, data, ctx) {
        try {
            await this.assertSettingsAccess(ctx, true);
            const schedule = await this.db.leave_policy.findFirst({
                where: { id, owner_id },
            });
            if (!schedule) {
                throw (0, utils_1.createGeneralError)('Leave policy not found', 'root', common_1.HttpStatus.NOT_FOUND);
            }
            const updatedSchedule = await this.db.leave_policy.update({
                where: { id },
                data: {
                    ...data,
                },
            });
            const parsedResult = configurations_dto_1.leavePolicyResponseSchema.safeParse(updatedSchedule);
            if (!parsedResult.success) {
                throw (0, utils_1.createGeneralError)(parsedResult.error.message, 'leave_policy', common_1.HttpStatus.BAD_REQUEST);
            }
            const parsedData = parsedResult.data;
            config_1.logger.info(`Leave policy updated successfully: ${JSON.stringify(parsedData)}`);
            return {
                data: parsedData,
                message: 'Leave policy updated successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateLeavePolicy: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getWorkDaySchedules(owner_id, ctx) {
        try {
            await this.assertSettingsAccess(ctx, false);
            let schedules = await this.db.work_day_schedules.findMany({
                where: { owner_id },
                orderBy: { day_of_week: 'asc' },
            });
            if (!schedules || schedules.length === 0) {
                const defaultDays = [
                    { day: 0, active: true },
                    { day: 1, active: true },
                    { day: 2, active: true },
                    { day: 3, active: true },
                    { day: 4, active: true },
                    { day: 5, active: false },
                    { day: 6, active: false },
                ];
                for (const item of defaultDays) {
                    await this.db.work_day_schedules.create({
                        data: {
                            owner_id,
                            day_of_week: item.day,
                            is_active: item.active,
                            start_time: '09:00',
                            end_time: '17:00',
                            break_start: '13:00',
                            break_end: '14:00',
                            grace_period_minutes: 15,
                        },
                    });
                }
                schedules = await this.db.work_day_schedules.findMany({
                    where: { owner_id },
                    orderBy: { day_of_week: 'asc' },
                });
            }
            return {
                status: common_1.HttpStatus.OK,
                message: 'Work day schedules retrieved successfully',
                data: schedules,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getWorkDaySchedules: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateWorkDaySchedules(owner_id, body, ctx) {
        try {
            await this.assertSettingsAccess(ctx, true);
            for (const item of body.schedules) {
                const existing = await this.db.work_day_schedules.findFirst({
                    where: {
                        owner_id,
                        day_of_week: item.day_of_week,
                    },
                });
                if (existing) {
                    await this.db.work_day_schedules.update({
                        where: { id: existing.id },
                        data: {
                            is_active: item.is_active,
                            start_time: item.start_time,
                            end_time: item.end_time,
                            break_start: item.break_start ?? null,
                            break_end: item.break_end ?? null,
                            grace_period_minutes: item.grace_period_minutes ?? 15,
                        },
                    });
                }
                else {
                    await this.db.work_day_schedules.create({
                        data: {
                            owner_id,
                            day_of_week: item.day_of_week,
                            is_active: item.is_active,
                            start_time: item.start_time,
                            end_time: item.end_time,
                            break_start: item.break_start ?? null,
                            break_end: item.break_end ?? null,
                            grace_period_minutes: item.grace_period_minutes ?? 15,
                        },
                    });
                }
            }
            const allSchedules = await this.db.work_day_schedules.findMany({
                where: { owner_id },
                orderBy: { day_of_week: 'asc' },
            });
            return {
                status: common_1.HttpStatus.OK,
                message: 'Work day schedules updated successfully',
                data: allSchedules,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateWorkDaySchedules: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getAttendanceValidationSettings(owner_id, _ctx) {
        try {
            let settings = await this.db.attendance_settings.findFirst({
                where: { owner_id },
            });
            if (!settings) {
                settings = await this.db.attendance_settings.create({
                    data: {
                        owner_id,
                        enforce_ip_whitelist: false,
                        enforce_location: false,
                        location_name: 'Main Campus',
                        latitude: null,
                        longitude: null,
                        radius_meters: 100,
                    },
                });
            }
            const { data, error } = configurations_dto_1.attendanceValidationSettingsResponseSchema.safeParse(settings);
            if (error) {
                throw new config_1.ErrorResponse(error.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return {
                data: data,
                message: 'Attendance validation settings fetched successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getAttendanceValidationSettings: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateAttendanceValidationSettings(owner_id, payload, ctx) {
        try {
            if (ctx) {
                await this.assertSettingsAccess(ctx, true);
            }
            const existing = await this.db.attendance_settings.findFirst({
                where: { owner_id },
            });
            let updated;
            if (existing) {
                updated = await this.db.attendance_settings.update({
                    where: { id: existing.id },
                    data: {
                        ...(payload.enforce_ip_whitelist !== undefined
                            ? { enforce_ip_whitelist: payload.enforce_ip_whitelist }
                            : {}),
                        ...(payload.enforce_location !== undefined
                            ? { enforce_location: payload.enforce_location }
                            : {}),
                        ...(payload.location_name !== undefined
                            ? { location_name: payload.location_name.trim() }
                            : {}),
                        ...(payload.latitude !== undefined
                            ? { latitude: payload.latitude }
                            : {}),
                        ...(payload.longitude !== undefined
                            ? { longitude: payload.longitude }
                            : {}),
                        ...(payload.radius_meters !== undefined
                            ? { radius_meters: payload.radius_meters }
                            : {}),
                    },
                });
            }
            else {
                updated = await this.db.attendance_settings.create({
                    data: {
                        owner_id,
                        enforce_ip_whitelist: payload.enforce_ip_whitelist ?? false,
                        enforce_location: payload.enforce_location ?? false,
                        location_name: payload.location_name?.trim() || 'Main Campus',
                        latitude: payload.latitude ?? null,
                        longitude: payload.longitude ?? null,
                        radius_meters: payload.radius_meters ?? 100,
                    },
                });
            }
            const { data, error } = configurations_dto_1.attendanceValidationSettingsResponseSchema.safeParse(updated);
            if (error) {
                throw new config_1.ErrorResponse(error.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return {
                data: data,
                message: 'Attendance validation settings updated successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateAttendanceValidationSettings: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
};
exports.ConfigurationsService = ConfigurationsService;
exports.ConfigurationsService = ConfigurationsService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.DatabaseService,
        config_1.UploadService,
        permission_resolver_service_1.PermissionResolverService,
        org_timezone_service_1.OrgTimezoneService])
], ConfigurationsService);
//# sourceMappingURL=configurations.service.js.map