import { HttpStatus, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Not } from 'typeorm';
import { PermissionUserContext } from '../../common/access-control/permission-context.types';
import {
  assertScopedAction,
  assertToggle,
  EffectiveDataFilter,
  isSelfMemberRequest,
  resolveDataScope,
  stripSelfMemberUpdateFields,
} from '../../common/access-control/permission-resolver.helpers';
import { PermissionResolverService } from '../../common/access-control/permission-resolver.service';
import {
  DatabaseService,
  envConfig,
  ErrorResponse,
  HashService,
  logger,
  MailService,
  Status,
  UploadService,
} from '../../config';
import { AppString } from '../../constant/app-string';
import { createGeneralError } from '../../utils';
import { AccessControlService } from '../access-control/access-control.service';
import { DevicesService } from '../devices/devices.service';
import {
  createMemberDto,
  filterMembersDto,
  memberListResponsesSchema,
  memberOptionSchema,
  memberResponseSchema,
  membersResponseSchema,
  signinMemberDto,
  updateMemberDto,
} from './members.dto';
import { MembersHelper } from './members.helper';

@Injectable()
export class MembersService {
  constructor(
    private readonly db: DatabaseService,
    private readonly hashService: HashService,
    private readonly jwt: JwtService,
    private readonly mailService: MailService,
    private readonly uploadService: UploadService,
    private readonly membersHelper: MembersHelper,
    private readonly accessControlService: AccessControlService,
    private readonly permissionResolver: PermissionResolverService,
    private readonly devicesService: DevicesService,
  ) {}

  private async getPermissions(ctx: PermissionUserContext) {
    return this.permissionResolver.resolveForUser(ctx);
  }

  private buildMembersScopeFilter(
    filter: EffectiveDataFilter,
    actorMemberId: string,
  ): Record<string, unknown> {
    if (filter === 'own') {
      return { id: actorMemberId };
    }

    if (filter === 'all_others') {
      return { id: Not(actorMemberId) };
    }

    return {};
  }

  private deriveLegacyRoleFromAccessRole(slug: string): 'admin' | 'member' {
    return slug === 'admin' ? 'admin' : 'member';
  }

  private async resolveAndValidateAccessRole(
    owner_id: string,
    access_role_id: string,
    ctx?: PermissionUserContext,
  ) {
    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 createGeneralError(
        'Access role not found',
        'access_role_id',
        HttpStatus.BAD_REQUEST,
      );
    }

    if (accessRole.slug === 'owner') {
      throw createGeneralError(
        'Owner role cannot be assigned to members',
        'access_role_id',
        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),
    };
  }

  private async assertCanAssignAccessRole(
    owner_id: string,
    ctx: PermissionUserContext,
    targetHierarchy: number,
  ) {
    const actorRoleId = await this.permissionResolver.resolveAccessRoleId(ctx);
    if (!actorRoleId) {
      throw createGeneralError(
        'You do not have permission to assign access roles',
        'access_role_id',
        HttpStatus.FORBIDDEN,
      );
    }

    const actorRole = await this.db.access_roles.findFirst({
      where: { id: actorRoleId, owner_id },
      select: { hierarchy: true },
    });

    if (!actorRole || targetHierarchy >= actorRole.hierarchy) {
      throw createGeneralError(
        'You cannot assign a role equal to or higher than your own',
        'access_role_id',
        HttpStatus.FORBIDDEN,
      );
    }
  }

  private async assertActiveMemberForSelf(
    owner_id: string,
    ctx: PermissionUserContext,
    targetMemberId: string,
  ) {
    if (!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 createGeneralError(
        'Your account is not active',
        'status',
        HttpStatus.FORBIDDEN,
      );
    }
  }

  private async resolveMemberAccessRoleId(
    owner_id: string,
    role: string,
    access_role_id?: string | null,
  ) {
    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: signinMemberDto, clientIp?: string) {
    try {
      const orConditions = [];
      const cleanEmail = data?.email?.trim()?.toLowerCase();
      const cleanEmployeeId = data?.employee_id?.trim();

      if (cleanEmail) {
        orConditions.push({ email: cleanEmail, status: Status.active });
      }
      if (cleanEmployeeId) {
        orConditions.push({
          employee_id: cleanEmployeeId,
          status: Status.active,
        });
      }

      if (orConditions.length === 0) {
        throw createGeneralError(
          AppString.INVALID_CREDENTIALS,
          'root',
          HttpStatus.EXPECTATION_FAILED,
        );
      }

      const member = await this.db.members.findFirst({
        where: {
          OR: orConditions,
        },
      });

      if (!member) {
        logger.error(orConditions);
        throw createGeneralError(
          AppString.INVALID_CREDENTIALS,
          'root',
          HttpStatus.EXPECTATION_FAILED,
        );
      }

      const isPasswordValid = await this.hashService.comparePasswords(
        data?.password,
        member.password,
      );

      if (!isPasswordValid) {
        logger.error(AppString.INVALID_CREDENTIALS);
        throw createGeneralError(
          AppString.INVALID_CREDENTIALS,
          'root',
          HttpStatus.EXPECTATION_FAILED,
        );
      }

      // ✅ Auto-bind device on login (if unbound) or validate/update activity
      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) {
            logger.warn(
              `Device mismatch/warning on login for member ${member.id}: ${deviceCheck.message}`,
            );
          }
        } catch (deviceErr) {
          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 } = memberOptionSchema.safeParse({
        ...member,
        access_token: token,
      });

      return {
        data: parsedMember,
        message: 'Signin successful',
        status: HttpStatus.OK,
        details: null,
      };
    } catch (error) {
      logger.error(`Error in signinMember: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async getMembers(
    owner_id: string,
    ctx: PermissionUserContext,
    dataScope?: 'own' | 'all',
  ) {
    try {
      const permissions = await this.getPermissions(ctx);
      assertToggle(permissions, 'members.access');
      const scopeFilter = 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, // ✅ load full relation, pick fields below
        },
      });

      if (!members || members.length === 0) {
        throw createGeneralError(
          'No members found',
          'members',
          HttpStatus.NOT_FOUND,
        );
      }

      const { data: parsedMembers } = membersResponseSchema.safeParse(members);

      return {
        data: parsedMembers,
        message: 'Members retrieved successfully',
        status: HttpStatus.OK,
        details: null,
      };
    } catch (error) {
      logger.error(`Error in getMembers: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async getMemberById(
    id: string,
    owner_id: string,
    ctx: PermissionUserContext,
  ) {
    try {
      const isSelf = isSelfMemberRequest(ctx, id);

      if (isSelf) {
        await this.assertActiveMemberForSelf(owner_id, ctx, id);
      } else {
        const permissions = await this.getPermissions(ctx);
        assertToggle(permissions, 'members.access');
        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, // ✅ load full relation, pick fields below
        },
      });
      if (!member) {
        throw createGeneralError(
          'Member not found',
          'member',
          HttpStatus.NOT_FOUND,
        );
      }
      const { data: parsedMember } = memberResponseSchema.safeParse(member);
      return {
        data: parsedMember,
        message: 'Member retrieved successfully',
        status: HttpStatus.OK,
        details: null,
      };
    } catch (error) {
      logger.error(`Error in getMemberById: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async getMembersByFilters(
    query: filterMembersDto,
    owner_id: string,
    ctx: PermissionUserContext,
  ) {
    try {
      const permissions = await this.getPermissions(ctx);
      assertToggle(permissions, 'members.access');
      const scopeFilter = 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: Record<string, unknown> = {
        owner_id,
        ...memberScopeFilter,
      };

      if (query.status) {
        where.status = query.status;
      } else if (typeof query.attention === 'boolean') {
        where.status = query.attention ? Not('active') : 'active'; // ✅ Use Not() directly
      }

      if (query.department) {
        where.department_id = query.department; // ✅ Filter by ID directly, not nested object
      }

      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 = await this.db.members.findMany({
      //   where,
      //   include: {
      //     work_experiences: true,
      //     educations: true,
      //     department: true, // ✅ Load full relation, pick fields below
      //     location: true,
      //     employment_type: true,
      //     designation: true,
      //     hiring_source: true,
      //   },
      //   skip,
      //   take: limit,
      //   orderBy: { created_at: 'asc' },
      // });
      const [members, total] = await Promise.all([
        this.db.members.findMany({
          where,
          skip,
          include: {
            work_experiences: true,
            educations: true,
            department: true, // ✅ Load full relation, pick fields below
            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 } =
        membersResponseSchema.safeParse(members);

      console.log({ length: total });

      return this.membersHelper.buildResponse(
        parsedMembers,
        total,
        page,
        limit,
      );
    } catch (error) {
      logger.error(`Error in getMembersByFilters: ${String(error)}`);
      if (error instanceof ErrorResponse) throw error;
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async getCalculatedMembersByFilters(
    query: filterMembersDto,
    owner_id: string,
    ctx: PermissionUserContext,
  ) {
    try {
      const permissions = await this.getPermissions(ctx);
      assertToggle(permissions, 'members.access');
      const scopeFilter = 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: Record<string, unknown> = { ...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 createGeneralError(
          'Working schedule not found for this owner',
          'working_schedule',
          HttpStatus.NOT_FOUND,
        );
      }

      if (!leavePolicy) {
        throw createGeneralError(
          'Leave policy not found for this owner',
          'leave_policy',
          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<string, number>(
        attendanceGroups.map((r) => [r.member_id, Number(r._count._all)]),
      );

      type LeaveRange = { start_date: Date; end_date: Date | null };

      const leaveRowsMap = (
        leaveRows as Array<{
          member_id: string;
          start_date: Date;
          end_date: Date | null;
        }>
      ).reduce<Map<string, LeaveRange[]>>((acc, leave) => {
        const bucket: LeaveRange[] = 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<string, LeaveRange[]>());

      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 } =
        memberListResponsesSchema.safeParse(enrichedMembers);

      return this.membersHelper.buildResponse(
        parsedMembers,
        total,
        page,
        limit,
      );
    } catch (error) {
      logger.error(`Error in getMembersByFilters: ${String(error)}`);
      if (error instanceof ErrorResponse) throw error;
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async createMember(
    data: createMemberDto,
    owner_id: string,
    ctx: PermissionUserContext,
  ) {
    try {
      const permissions = await this.getPermissions(ctx);
      assertToggle(permissions, 'members.access');
      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 createGeneralError(
          'Member with the same email or employee ID already exists',
          'email',
          HttpStatus.CONFLICT,
        );
      }
      const { profile } = 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 createGeneralError(
          'Access role is required',
          'access_role_id',
          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 }
            : {}),
        },
      });

      // Create work experiences if provided
      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,
          })),
        });
      }

      // Fetch member with work experiences
      const memberWithExperiences = await this.db.members.findUnique({
        where: { id: member.id, owner_id },
        include: { work_experiences: true, educations: true },
      });

      const { data: parsedOwner } = 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: HttpStatus.CREATED,
        details: null,
      };
      // Optionally, send a welcome email to the new member
    } catch (error) {
      logger.error(`Error in resendOtp: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async updateMember(
    id: string,
    data: updateMemberDto,
    owner_id: string,
    ctx: PermissionUserContext,
  ) {
    try {
      const isSelf = isSelfMemberRequest(ctx, id);

      if (isSelf) {
        await this.assertActiveMemberForSelf(owner_id, ctx, id);
      } else {
        const permissions = await this.getPermissions(ctx);
        assertToggle(permissions, 'members.access');
        assertScopedAction(permissions, 'members.update', id, ctx.sub);
      }

      const updateData = isSelf ? stripSelfMemberUpdateFields(data) : data;

      const existingMember = await this.db.members.findUnique({
        where: { id, owner_id },
      });
      if (!existingMember) {
        throw createGeneralError(
          'Member not found',
          'member',
          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 as any);
      }

      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 } = envConfig().server;

      let accessRoleUpdate: {
        access_role_id?: string | null;
        role?: 'admin' | 'member';
      } = {};

      if (updateData.access_role_id !== undefined) {
        if (!updateData.access_role_id) {
          throw createGeneralError(
            'Access role cannot be removed',
            'access_role_id',
            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 } =
        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: HttpStatus.OK,
        details: null,
      };
    } catch (error) {
      logger.error(`Error in updateMember: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }

  async deleteMember(id: string, owner_id: string, ctx: PermissionUserContext) {
    try {
      if (isSelfMemberRequest(ctx, id)) {
        throw createGeneralError(
          'You cannot delete your own account',
          'members.delete',
          HttpStatus.FORBIDDEN,
        );
      }

      const permissions = await this.getPermissions(ctx);
      assertToggle(permissions, 'members.access');
      assertScopedAction(permissions, 'members.delete', id, ctx.sub);

      const existingMember = await this.db.members.findUnique({
        where: { id, owner_id },
      });

      if (!existingMember) {
        throw createGeneralError(
          'Member not found',
          'member',
          HttpStatus.NOT_FOUND,
        );
      }

      await this.db.members.update({
        where: { id, owner_id },
        data: { status: 'deleted' },
      });

      // // Self-referencing relation cleanup: remove manager link from reportees.
      // await this.db.members.updateMany({
      //   where: { reporting_manager_id: id, owner_id },
      //   data: { reporting_manager_id: null },
      // });

      // // Department head relation cleanup before member deletion.
      // await this.db.departments.updateMany({
      //   where: { department_head_id: id, owner_id },
      //   data: { department_head_id: null },
      // });

      // // Remove child rows that reference this member.
      // await this.db.work_experiences.deleteMany({
      //   where: { member_id: id, owner_id },
      // });

      // await this.db.educations.deleteMany({
      //   where: { member_id: id, owner_id },
      // });

      // await this.db.leaves.deleteMany({
      //   where: { member_id: id, owner_id },
      // });

      // // attendance_breaks are already cascade-deleted from attendances.
      // await this.db.attendances.deleteMany({
      //   where: { member_id: id, owner_id },
      // });

      // await this.db.members.delete({
      //   where: { id },
      // });

      return {
        data: null,
        message: 'Member deleted successfully',
        status: HttpStatus.OK,
        details: null,
      };
    } catch (error) {
      logger.error(`Error in deleteMember: ${String(error)}`);
      if (error instanceof ErrorResponse) {
        throw error;
      }
      throw createGeneralError(String(error), 'root', HttpStatus.BAD_REQUEST);
    }
  }
}
