import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
import { SetStaffScheduleDto, CreateStaffExceptionDto } from '../dto/staff-schedule.dto';

@Injectable()
export class StaffScheduleService {
  constructor(private readonly prisma: PrismaService) {}

  // ─── Weekly Schedule ────────────────────────────────────────

  async getSchedule(clubId: string, staffId: string) {
    return this.prisma.bookingStaffSchedule.findMany({
      where: { clubId, staffId },
      orderBy: { dayOfWeek: 'asc' },
    });
  }

  async setSchedule(clubId: string, staffId: string, dto: SetStaffScheduleDto) {
    // Replace entire weekly schedule
    await this.prisma.bookingStaffSchedule.deleteMany({
      where: { clubId, staffId },
    });

    if (dto.slots.length === 0) return [];

    await this.prisma.bookingStaffSchedule.createMany({
      data: dto.slots.map((slot) => ({
        clubId,
        staffId,
        dayOfWeek: slot.dayOfWeek,
        startTime: slot.startTime,
        endTime: slot.endTime,
        breakStart: slot.breakStart,
        breakEnd: slot.breakEnd,
        isActive: slot.isActive ?? true,
      })),
    });

    return this.getSchedule(clubId, staffId);
  }

  // ─── Exceptions (day off / extra workday) ───────────────────

  async getExceptions(clubId: string, staffId: string, from?: Date, to?: Date) {
    return this.prisma.bookingStaffException.findMany({
      where: {
        clubId,
        staffId,
        ...(from && to ? { date: { gte: from, lte: to } } : {}),
      },
      orderBy: { date: 'asc' },
    });
  }

  async createException(clubId: string, staffId: string, dto: CreateStaffExceptionDto) {
    return this.prisma.bookingStaffException.upsert({
      where: {
        clubId_staffId_date: {
          clubId,
          staffId,
          date: new Date(dto.date),
        },
      },
      create: {
        clubId,
        staffId,
        date: new Date(dto.date),
        isWorkday: dto.isWorkday ?? false,
        startTime: dto.startTime,
        endTime: dto.endTime,
        reason: dto.reason,
      },
      update: {
        isWorkday: dto.isWorkday ?? false,
        startTime: dto.startTime,
        endTime: dto.endTime,
        reason: dto.reason,
      },
    });
  }

  async deleteException(id: string) {
    const ex = await this.prisma.bookingStaffException.findUnique({ where: { id } });
    if (!ex) throw new NotFoundException(`Exception ${id} not found`);
    await this.prisma.bookingStaffException.delete({ where: { id } });
  }

  // ─── Get all staff with their schedule for a club ───────────

  async getAllStaffSchedules(clubId: string) {
    const schedules = await this.prisma.bookingStaffSchedule.findMany({
      where: { clubId, isActive: true },
      include: {
        staff: { select: { id: true, firstName: true, lastName: true, avatarUrl: true } },
      },
      orderBy: [{ staffId: 'asc' }, { dayOfWeek: 'asc' }],
    });

    // Group by staff
    const byStaff = new Map<string, any>();
    for (const s of schedules) {
      if (!byStaff.has(s.staffId)) {
        byStaff.set(s.staffId, {
          staff: s.staff,
          slots: [],
        });
      }
      // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
      byStaff.get(s.staffId).slots.push({
        dayOfWeek: s.dayOfWeek,
        startTime: s.startTime,
        endTime: s.endTime,
        breakStart: s.breakStart,
        breakEnd: s.breakEnd,
      });
    }

    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
    return Array.from(byStaff.values());
  }
}
