"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.MembersService = void 0;
const common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
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 config_1 = require("../../config");
const app_string_1 = require("../../constant/app-string");
const utils_1 = require("../../utils");
const access_control_service_1 = require("../access-control/access-control.service");
const devices_service_1 = require("../devices/devices.service");
const members_dto_1 = require("./members.dto");
const members_helper_1 = require("./members.helper");
let MembersService = class MembersService {
    constructor(db, hashService, jwt, mailService, uploadService, membersHelper, accessControlService, permissionResolver, devicesService) {
        this.db = db;
        this.hashService = hashService;
        this.jwt = jwt;
        this.mailService = mailService;
        this.uploadService = uploadService;
        this.membersHelper = membersHelper;
        this.accessControlService = accessControlService;
        this.permissionResolver = permissionResolver;
        this.devicesService = devicesService;
    }
    async getPermissions(ctx) {
        return this.permissionResolver.resolveForUser(ctx);
    }
    buildMembersScopeFilter(filter, actorMemberId) {
        if (filter === 'own') {
            return { id: actorMemberId };
        }
        if (filter === 'all_others') {
            return { id: (0, typeorm_1.Not)(actorMemberId) };
        }
        return {};
    }
    deriveLegacyRoleFromAccessRole(slug) {
        return slug === 'admin' ? 'admin' : 'member';
    }
    async resolveAndValidateAccessRole(owner_id, access_role_id, ctx) {
        const accessRole = await this.db.access_roles.findFirst({
            where: { id: access_role_id, owner_id },
            select: { id: true, slug: true, hierarchy: true },
        });
        if (!accessRole) {
            throw (0, utils_1.createGeneralError)('Access role not found', 'access_role_id', common_1.HttpStatus.BAD_REQUEST);
        }
        if (accessRole.slug === 'owner') {
            throw (0, utils_1.createGeneralError)('Owner role cannot be assigned to members', 'access_role_id', common_1.HttpStatus.BAD_REQUEST);
        }
        if (ctx && ctx.role !== 'owner') {
            await this.assertCanAssignAccessRole(owner_id, ctx, accessRole.hierarchy);
        }
        return {
            id: accessRole.id,
            legacyRole: this.deriveLegacyRoleFromAccessRole(accessRole.slug),
        };
    }
    async assertCanAssignAccessRole(owner_id, ctx, targetHierarchy) {
        const actorRoleId = await this.permissionResolver.resolveAccessRoleId(ctx);
        if (!actorRoleId) {
            throw (0, utils_1.createGeneralError)('You do not have permission to assign access roles', 'access_role_id', common_1.HttpStatus.FORBIDDEN);
        }
        const actorRole = await this.db.access_roles.findFirst({
            where: { id: actorRoleId, owner_id },
            select: { hierarchy: true },
        });
        if (!actorRole || targetHierarchy >= actorRole.hierarchy) {
            throw (0, utils_1.createGeneralError)('You cannot assign a role equal to or higher than your own', 'access_role_id', common_1.HttpStatus.FORBIDDEN);
        }
    }
    async assertActiveMemberForSelf(owner_id, ctx, targetMemberId) {
        if (!(0, permission_resolver_helpers_1.isSelfMemberRequest)(ctx, targetMemberId)) {
            return;
        }
        const member = await this.db.members.findFirst({
            where: { id: targetMemberId, owner_id },
            select: { status: true },
        });
        if (!member || member.status !== 'active') {
            throw (0, utils_1.createGeneralError)('Your account is not active', 'status', common_1.HttpStatus.FORBIDDEN);
        }
    }
    async resolveMemberAccessRoleId(owner_id, role, access_role_id) {
        if (access_role_id) {
            const resolved = await this.resolveAndValidateAccessRole(owner_id, access_role_id);
            return resolved.id;
        }
        return this.accessControlService.resolveAccessRoleIdBySlug(owner_id, role);
    }
    async signinMember(data, clientIp) {
        try {
            const orConditions = [];
            const cleanEmail = data?.email?.trim()?.toLowerCase();
            const cleanEmployeeId = data?.employee_id?.trim();
            if (cleanEmail) {
                orConditions.push({ email: cleanEmail, status: config_1.Status.active });
            }
            if (cleanEmployeeId) {
                orConditions.push({
                    employee_id: cleanEmployeeId,
                    status: config_1.Status.active,
                });
            }
            if (orConditions.length === 0) {
                throw (0, utils_1.createGeneralError)(app_string_1.AppString.INVALID_CREDENTIALS, 'root', common_1.HttpStatus.EXPECTATION_FAILED);
            }
            const member = await this.db.members.findFirst({
                where: {
                    OR: orConditions,
                },
            });
            if (!member) {
                config_1.logger.error(orConditions);
                throw (0, utils_1.createGeneralError)(app_string_1.AppString.INVALID_CREDENTIALS, 'root', common_1.HttpStatus.EXPECTATION_FAILED);
            }
            const isPasswordValid = await this.hashService.comparePasswords(data?.password, member.password);
            if (!isPasswordValid) {
                config_1.logger.error(app_string_1.AppString.INVALID_CREDENTIALS);
                throw (0, utils_1.createGeneralError)(app_string_1.AppString.INVALID_CREDENTIALS, 'root', common_1.HttpStatus.EXPECTATION_FAILED);
            }
            if (data?.device_id && member.id && member.owner_id) {
                try {
                    const deviceCheck = await this.devicesService.validateOrBindDevice(member.id, member.owner_id, data.device_id, data.device_name, clientIp);
                    if (!deviceCheck.valid) {
                        config_1.logger.warn(`Device mismatch/warning on login for member ${member.id}: ${deviceCheck.message}`);
                    }
                }
                catch (deviceErr) {
                    config_1.logger.warn(`Device check error during login: ${deviceErr}`);
                }
            }
            const token = this.jwt.sign({
                sub: member.id,
                owner_id: member.owner_id,
                email: member.email,
                role: member.role,
                access_role_id: member.access_role_id,
            });
            const { data: parsedMember } = members_dto_1.memberOptionSchema.safeParse({
                ...member,
                access_token: token,
            });
            return {
                data: parsedMember,
                message: 'Signin successful',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in signinMember: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getMembers(owner_id, ctx, dataScope) {
        try {
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'members.view', dataScope, ctx);
            const memberScopeFilter = this.buildMembersScopeFilter(scopeFilter, ctx.sub);
            const members = await this.db.members.findMany({
                where: { owner_id, status: 'active', ...memberScopeFilter },
                include: {
                    department: true,
                },
            });
            if (!members || members.length === 0) {
                throw (0, utils_1.createGeneralError)('No members found', 'members', common_1.HttpStatus.NOT_FOUND);
            }
            const { data: parsedMembers } = members_dto_1.membersResponseSchema.safeParse(members);
            return {
                data: parsedMembers,
                message: 'Members retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getMembers: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getMemberById(id, owner_id, ctx) {
        try {
            const isSelf = (0, permission_resolver_helpers_1.isSelfMemberRequest)(ctx, id);
            if (isSelf) {
                await this.assertActiveMemberForSelf(owner_id, ctx, id);
            }
            else {
                const permissions = await this.getPermissions(ctx);
                (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
                (0, permission_resolver_helpers_1.assertScopedAction)(permissions, 'members.view', id, ctx.sub);
            }
            const member = await this.db.members.findUnique({
                where: { id, owner_id },
                include: {
                    work_experiences: true,
                    educations: true,
                    department: true,
                },
            });
            if (!member) {
                throw (0, utils_1.createGeneralError)('Member not found', 'member', common_1.HttpStatus.NOT_FOUND);
            }
            const { data: parsedMember } = members_dto_1.memberResponseSchema.safeParse(member);
            return {
                data: parsedMember,
                message: 'Member retrieved successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in getMemberById: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getMembersByFilters(query, owner_id, ctx) {
        try {
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'members.view', query.data_scope, ctx);
            const memberScopeFilter = this.buildMembersScopeFilter(scopeFilter, ctx.sub);
            const page = query.page ?? 1;
            const limit = query.limit ?? 10;
            const skip = (page - 1) * limit;
            const where = {
                owner_id,
                ...memberScopeFilter,
            };
            if (query.status) {
                where.status = query.status;
            }
            else if (typeof query.attention === 'boolean') {
                where.status = query.attention ? (0, typeorm_1.Not)('active') : 'active';
            }
            if (query.department) {
                where.department_id = query.department;
            }
            if (query.search) {
                where.OR = [
                    { first_name: { contains: query.search } },
                    { last_name: { contains: query.search } },
                    { email: { contains: query.search } },
                    { employee_id: { contains: query.search } },
                    { nickname: { contains: query.search } },
                ];
            }
            const [members, total] = await Promise.all([
                this.db.members.findMany({
                    where,
                    skip,
                    include: {
                        work_experiences: true,
                        educations: true,
                        department: true,
                        location: true,
                        employment_type: true,
                        designation: true,
                        hiring_source: true,
                    },
                    take: limit,
                    orderBy: { created_at: 'asc' },
                }),
                this.db.members.count({ where }),
            ]);
            if (members.length === 0) {
                return this.membersHelper.buildResponse([], 0, page, limit);
            }
            const { data: parsedMembers, error } = members_dto_1.membersResponseSchema.safeParse(members);
            console.log({ length: total });
            return this.membersHelper.buildResponse(parsedMembers, total, page, limit);
        }
        catch (error) {
            config_1.logger.error(`Error in getMembersByFilters: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async getCalculatedMembersByFilters(query, owner_id, ctx) {
        try {
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
            const scopeFilter = (0, permission_resolver_helpers_1.resolveDataScope)(permissions, 'members.view', query.data_scope, ctx);
            const memberScopeFilter = this.buildMembersScopeFilter(scopeFilter, ctx.sub);
            const page = query.page ?? 1;
            const limit = query.limit ?? 10;
            const skip = (page - 1) * limit;
            const today = this.membersHelper.normalizeDate(new Date());
            const yearStart = this.membersHelper.startOfYear(today);
            const where = { ...memberScopeFilter };
            if (query.status) {
                where.status = query.status;
            }
            else if (typeof query.attention === 'boolean') {
                where.status = query.attention ? { not: 'active' } : 'active';
            }
            if (query.department) {
                where.department = { name: { contains: query.department } };
            }
            if (query.search) {
                where.OR = [
                    { first_name: { contains: query.search } },
                    { last_name: { contains: query.search } },
                    { email: { contains: query.search } },
                    { employee_id: { contains: query.search } },
                    { nickname: { contains: query.search } },
                ];
            }
            const [members, total, holidayRows, workingSchedule, leavePolicy] = await Promise.all([
                this.db.members.findMany({
                    where: { ...where, owner_id },
                    select: {
                        id: true,
                        email: true,
                        employee_id: true,
                        image: true,
                        nickname: true,
                        first_name: true,
                        last_name: true,
                        role: true,
                        status: true,
                        department_id: true,
                        designation_id: true,
                        location_id: true,
                        employment_type_id: true,
                        hiring_source_id: true,
                        department: { select: { id: true, name: true } },
                        location: { select: { id: true, name: true } },
                        employment_type: { select: { id: true, name: true } },
                        designation: { select: { id: true, name: true } },
                        hiring_source: { select: { id: true, name: true } },
                        date_of_joining: true,
                    },
                    skip,
                    take: limit,
                    orderBy: { created_at: 'asc' },
                }),
                this.db.members.count({ where: { ...where, owner_id } }),
                this.db.holidays.findMany({
                    where: {
                        owner_id,
                        OR: [
                            {
                                is_recurring: false,
                                start_date: { lte: today },
                                end_date: { gte: yearStart },
                            },
                            { is_recurring: true, start_date: { lte: today } },
                        ],
                    },
                    select: { start_date: true, end_date: true, is_recurring: true },
                }),
                this.db.working_schedule.findFirst({
                    where: { owner_id },
                    select: {
                        working_days: true,
                        working_hours_per_day: true,
                    },
                }),
                this.db.leave_policy.findFirst({
                    where: { owner_id },
                    select: {
                        annual_leave_days: true,
                        sick_leave_days: true,
                        casual_leave_days: true,
                        maternity_leave_days: true,
                        paternity_leave_days: true,
                        personal_leave_days: true,
                        compensatory_leave_days: true,
                    },
                }),
            ]);
            if (!workingSchedule) {
                throw (0, utils_1.createGeneralError)('Working schedule not found for this owner', 'working_schedule', common_1.HttpStatus.NOT_FOUND);
            }
            if (!leavePolicy) {
                throw (0, utils_1.createGeneralError)('Leave policy not found for this owner', 'leave_policy', common_1.HttpStatus.NOT_FOUND);
            }
            const workingDayIndexes = this.membersHelper.parseWorkingDays(workingSchedule.working_days);
            const workingHoursPerDay = workingSchedule.working_hours_per_day;
            const assignedLeaveDays = this.membersHelper.calculateAssignedLeaveDays(leavePolicy);
            const holidayDates = this.membersHelper.buildHolidayDateSet(yearStart, today, holidayRows);
            if (members.length === 0) {
                return this.membersHelper.buildResponse([], total, page, limit);
            }
            const memberIds = members.map((m) => m.id);
            const [attendanceGroups, leaveRows] = await Promise.all([
                this.db.attendances.groupBy({
                    by: ['member_id'],
                    where: {
                        owner_id,
                        member_id: { in: memberIds },
                        date: { gte: yearStart, lte: today },
                        status: { in: ['present', 'late', 'half_day', 'remote'] },
                    },
                    _count: { _all: true },
                }),
                this.db.leaves.findMany({
                    where: {
                        owner_id,
                        member_id: { in: memberIds },
                        status: 'approved',
                        start_date: { lte: today },
                        end_date: { gte: yearStart },
                    },
                    select: { member_id: true, start_date: true, end_date: true },
                }),
            ]);
            const attendanceCountMap = new Map(attendanceGroups.map((r) => [r.member_id, Number(r._count._all)]));
            const leaveRowsMap = leaveRows.reduce((acc, leave) => {
                const bucket = acc.get(leave.member_id) ?? [];
                bucket.push({
                    start_date: leave.start_date,
                    end_date: leave.end_date ?? null,
                });
                acc.set(leave.member_id, bucket);
                return acc;
            }, new Map());
            const enrichedMembers = members.map((member) => {
                const totalWorkingDays = this.membersHelper.countWorkingDays(yearStart, today, holidayDates, workingDayIndexes);
                const totalLeave = this.membersHelper.countLeaveDays(yearStart, today, leaveRowsMap.get(member.id) ?? []);
                const attendanceCount = attendanceCountMap.get(member.id) ?? 0;
                const attendancePct = totalWorkingDays > 0
                    ? +((attendanceCount / totalWorkingDays) * 100).toFixed(2)
                    : 0;
                return {
                    ...member,
                    attendance_percentage: attendancePct,
                    total_leave: totalLeave,
                    leave_balance: Math.max(assignedLeaveDays - totalLeave, 0),
                    total_working_days: totalWorkingDays,
                    total_working_hours: Number((totalWorkingDays * workingHoursPerDay).toFixed(2)),
                    assigned_leave: assignedLeaveDays,
                };
            });
            const { data: parsedMembers } = members_dto_1.memberListResponsesSchema.safeParse(enrichedMembers);
            return this.membersHelper.buildResponse(parsedMembers, total, page, limit);
        }
        catch (error) {
            config_1.logger.error(`Error in getMembersByFilters: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async createMember(data, owner_id, ctx) {
        try {
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.create');
            const existingMember = await this.db.members.findFirst({
                where: {
                    owner_id,
                    OR: [
                        ...(data?.email ? [{ email: data?.email }] : []),
                        ...(data?.employee_id ? [{ employee_id: data?.employee_id }] : []),
                    ],
                },
            });
            if (existingMember) {
                throw (0, utils_1.createGeneralError)('Member with the same email or employee ID already exists', 'email', common_1.HttpStatus.CONFLICT);
            }
            const { profile } = (0, config_1.envConfig)().server;
            let image = data?.image;
            if (image) {
                image = await this.uploadService.moveImage(image, 'members');
            }
            const hashedPassword = await this.hashService.hashPassword(data?.password);
            if (!data?.access_role_id) {
                throw (0, utils_1.createGeneralError)('Access role is required', 'access_role_id', common_1.HttpStatus.BAD_REQUEST);
            }
            const resolved = await this.resolveAndValidateAccessRole(owner_id, data.access_role_id, ctx);
            const member = await this.db.members.create({
                data: {
                    email: data?.email,
                    employee_id: data?.employee_id,
                    image: image ?? {
                        file_name: profile,
                        original_name: 'profile.webp',
                        file_size: 8192,
                        mime_type: 'image/webp',
                    },
                    nickname: data?.nickname,
                    role: resolved.legacyRole,
                    access_role_id: resolved.id,
                    first_name: data?.first_name,
                    last_name: data?.last_name,
                    password: hashedPassword,
                    about: data?.about,
                    expertise: data?.expertise,
                    work_email: data?.work_email,
                    father_name: data?.father_name,
                    mother_name: data?.mother_name,
                    marital_status: data?.marital_status,
                    emergency_contact_name: data?.emergency_contact_name,
                    emergency_contact_phone: data?.emergency_contact_phone,
                    emergency_contact_relationship: data?.emergency_contact_relationship,
                    work_phone: data?.work_phone,
                    phone: data?.phone,
                    present_address_line_one: data?.present_address_line_one,
                    present_address_line_two: data?.present_address_line_two,
                    present_address_city: data?.present_address_city,
                    present_address_country: data?.present_address_country,
                    present_address_state: data?.present_address_state,
                    present_address_zip_code: data?.present_address_zip_code,
                    permanent_address_line_one: data?.permanent_address_line_one,
                    permanent_address_line_two: data?.permanent_address_line_two,
                    permanent_address_city: data?.permanent_address_city,
                    permanent_address_country: data?.permanent_address_country,
                    permanent_address_state: data?.permanent_address_state,
                    permanent_address_zip_code: data?.permanent_address_zip_code,
                    owner_id,
                    ...(data?.gender ? { gender: data?.gender } : {}),
                    ...(data?.date_of_birth
                        ? { date_of_birth: data?.date_of_birth }
                        : {}),
                    ...(data?.date_of_joining
                        ? { date_of_joining: data?.date_of_joining }
                        : {}),
                    ...(data?.status ? { status: data?.status } : {}),
                    ...(data?.department_id
                        ? { department_id: data?.department_id }
                        : {}),
                    ...(data?.designation_id
                        ? { designation_id: data?.designation_id }
                        : {}),
                    ...(data?.location_id ? { location_id: data?.location_id } : {}),
                    ...(data?.employment_type_id
                        ? { employment_type_id: data?.employment_type_id }
                        : {}),
                    ...(data?.hiring_source_id
                        ? { hiring_source_id: data?.hiring_source_id }
                        : {}),
                    ...(data?.reporting_manager_id
                        ? { reporting_manager_id: data?.reporting_manager_id }
                        : {}),
                },
            });
            if (data?.work_experiences && data?.work_experiences.length > 0) {
                await this.db.work_experiences.createMany({
                    data: data?.work_experiences.map((exp) => ({
                        member_id: member.id,
                        owner_id,
                        company: exp.company,
                        position: exp.position,
                        start_date: exp.start_date,
                        end_date: exp.end_date ?? null,
                        description: exp.description ?? undefined,
                        relevant: exp.relevant ?? false,
                    })),
                });
            }
            if (data?.educations && data?.educations.length > 0) {
                await this.db.educations.createMany({
                    data: data?.educations.map((edu) => ({
                        member_id: member.id,
                        owner_id,
                        institution: edu.institution,
                        degree: edu.degree,
                        field: edu.field,
                        start_date: edu.start_date,
                        end_date: edu.end_date ?? null,
                        description: edu.description ?? undefined,
                        relevant: edu.relevant ?? false,
                    })),
                });
            }
            const memberWithExperiences = await this.db.members.findUnique({
                where: { id: member.id, owner_id },
                include: { work_experiences: true, educations: true },
            });
            const { data: parsedOwner } = members_dto_1.memberResponseSchema.safeParse(memberWithExperiences);
            this.mailService.sendMail('member-credentials-mail', data?.email, {
                name: data?.first_name + ' ' + data?.last_name,
                email: data?.email,
                password: data?.password,
                loginUrl: `https://team-tracker.rinov8.studio/auth/member/sign-in`,
            }, 'Welcome to the Team Tracker!');
            return {
                data: parsedOwner,
                message: 'Member created successfully',
                status: common_1.HttpStatus.CREATED,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in resendOtp: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async updateMember(id, data, owner_id, ctx) {
        try {
            const isSelf = (0, permission_resolver_helpers_1.isSelfMemberRequest)(ctx, id);
            if (isSelf) {
                await this.assertActiveMemberForSelf(owner_id, ctx, id);
            }
            else {
                const permissions = await this.getPermissions(ctx);
                (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
                (0, permission_resolver_helpers_1.assertScopedAction)(permissions, 'members.update', id, ctx.sub);
            }
            const updateData = isSelf ? (0, permission_resolver_helpers_1.stripSelfMemberUpdateFields)(data) : data;
            const existingMember = await this.db.members.findUnique({
                where: { id, owner_id },
            });
            if (!existingMember) {
                throw (0, utils_1.createGeneralError)('Member not found', 'member', common_1.HttpStatus.NOT_FOUND);
            }
            const shouldClearImage = updateData?.image === null;
            let image = updateData?.image;
            if (image) {
                image = await this.uploadService.moveImage(image, 'members');
            }
            if (shouldClearImage &&
                existingMember.image &&
                typeof existingMember.image === 'object' &&
                !Array.isArray(existingMember.image) &&
                'file_name' in existingMember.image &&
                'original_name' in existingMember.image &&
                'file_size' in existingMember.image &&
                'mime_type' in existingMember.image) {
                await this.uploadService.removeImage(existingMember.image);
            }
            const { department_id, designation_id, location_id, employment_type_id, hiring_source_id, reporting_manager_id, work_experiences, educations, gender, date_of_birth, date_of_joining, status, password, image: _image, role: _role, access_role_id: _accessRoleId, ...rest } = updateData;
            const hashedPassword = password
                ? await this.hashService.hashPassword(password)
                : undefined;
            const shouldConnectDepartment = typeof department_id === 'string';
            const shouldConnectDesignation = typeof designation_id === 'string';
            const shouldConnectLocation = typeof location_id === 'string';
            const shouldConnectEmploymentType = typeof employment_type_id === 'string';
            const shouldConnectHiringSource = typeof hiring_source_id === 'string';
            const shouldConnectReportingManager = typeof reporting_manager_id === 'string';
            const { profile } = (0, config_1.envConfig)().server;
            let accessRoleUpdate = {};
            if (updateData.access_role_id !== undefined) {
                if (!updateData.access_role_id) {
                    throw (0, utils_1.createGeneralError)('Access role cannot be removed', 'access_role_id', common_1.HttpStatus.BAD_REQUEST);
                }
                const resolved = await this.resolveAndValidateAccessRole(owner_id, updateData.access_role_id, ctx);
                accessRoleUpdate = {
                    access_role_id: resolved.id,
                    role: resolved.legacyRole,
                };
            }
            await this.db.members.update({
                where: { id, owner_id },
                data: {
                    ...rest,
                    ...accessRoleUpdate,
                    ...(shouldClearImage
                        ? {
                            image: {
                                file_name: profile,
                                original_name: 'profile.webp',
                                file_size: 8192,
                                mime_type: 'image/webp',
                            },
                        }
                        : {}),
                    ...(image ? { image } : {}),
                    ...(hashedPassword ? { password: hashedPassword } : {}),
                    ...(gender ? { gender } : {}),
                    ...(date_of_birth ? { date_of_birth } : {}),
                    ...(date_of_joining ? { date_of_joining } : {}),
                    ...(status ? { status } : {}),
                    ...(shouldConnectDepartment
                        ? {
                            department: {
                                connect: { id: department_id },
                            },
                        }
                        : {}),
                    ...(shouldConnectDesignation
                        ? {
                            designation: {
                                connect: { id: designation_id },
                            },
                        }
                        : {}),
                    ...(shouldConnectLocation
                        ? {
                            location: {
                                connect: { id: location_id },
                            },
                        }
                        : {}),
                    ...(shouldConnectEmploymentType
                        ? {
                            employment_type: {
                                connect: { id: employment_type_id },
                            },
                        }
                        : {}),
                    ...(shouldConnectHiringSource
                        ? {
                            hiring_source: {
                                connect: { id: hiring_source_id },
                            },
                        }
                        : {}),
                    ...(shouldConnectReportingManager
                        ? {
                            reporting_manager: {
                                connect: { id: reporting_manager_id },
                            },
                        }
                        : {}),
                },
            });
            if (work_experiences !== undefined) {
                await this.db.work_experiences.deleteMany({
                    where: { member_id: id, owner_id },
                });
                if (work_experiences.length > 0) {
                    await this.db.work_experiences.createMany({
                        data: work_experiences.map((exp) => ({
                            member_id: id,
                            owner_id,
                            company: exp.company,
                            position: exp.position,
                            start_date: exp.start_date,
                            end_date: exp.end_date ?? null,
                            description: exp.description ?? undefined,
                            relevant: exp.relevant ?? false,
                        })),
                    });
                }
            }
            if (educations !== undefined) {
                await this.db.educations.deleteMany({
                    where: { member_id: id, owner_id },
                });
                if (educations.length > 0) {
                    await this.db.educations.createMany({
                        data: educations.map((edu) => ({
                            member_id: id,
                            owner_id,
                            institution: edu.institution,
                            degree: edu.degree,
                            field: edu.field,
                            start_date: edu.start_date,
                            end_date: edu.end_date ?? null,
                            description: edu.description ?? undefined,
                            relevant: edu.relevant ?? false,
                        })),
                    });
                }
            }
            const updatedMember = await this.db.members.findUnique({
                where: { id, owner_id },
                include: {
                    work_experiences: true,
                    educations: true,
                },
            });
            const { data: parsedMember } = members_dto_1.memberResponseSchema.safeParse(updatedMember);
            if (password) {
                this.mailService.sendMail('member-credentials-mail', existingMember.email, {
                    name: existingMember.first_name + ' ' + existingMember.last_name,
                    email: existingMember.email,
                    password: password,
                    loginUrl: `https://team-tracker.rinov8.studio/auth/member/sign-in`,
                }, 'Your password has been updated');
            }
            return {
                data: parsedMember,
                message: 'Member updated successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in updateMember: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
    async deleteMember(id, owner_id, ctx) {
        try {
            if ((0, permission_resolver_helpers_1.isSelfMemberRequest)(ctx, id)) {
                throw (0, utils_1.createGeneralError)('You cannot delete your own account', 'members.delete', common_1.HttpStatus.FORBIDDEN);
            }
            const permissions = await this.getPermissions(ctx);
            (0, permission_resolver_helpers_1.assertToggle)(permissions, 'members.access');
            (0, permission_resolver_helpers_1.assertScopedAction)(permissions, 'members.delete', id, ctx.sub);
            const existingMember = await this.db.members.findUnique({
                where: { id, owner_id },
            });
            if (!existingMember) {
                throw (0, utils_1.createGeneralError)('Member not found', 'member', common_1.HttpStatus.NOT_FOUND);
            }
            await this.db.members.update({
                where: { id, owner_id },
                data: { status: 'deleted' },
            });
            return {
                data: null,
                message: 'Member deleted successfully',
                status: common_1.HttpStatus.OK,
                details: null,
            };
        }
        catch (error) {
            config_1.logger.error(`Error in deleteMember: ${String(error)}`);
            if (error instanceof config_1.ErrorResponse) {
                throw error;
            }
            throw (0, utils_1.createGeneralError)(String(error), 'root', common_1.HttpStatus.BAD_REQUEST);
        }
    }
};
exports.MembersService = MembersService;
exports.MembersService = MembersService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.DatabaseService,
        config_1.HashService,
        jwt_1.JwtService,
        config_1.MailService,
        config_1.UploadService,
        members_helper_1.MembersHelper,
        access_control_service_1.AccessControlService,
        permission_resolver_service_1.PermissionResolverService,
        devices_service_1.DevicesService])
], MembersService);
//# sourceMappingURL=members.service.js.map