import { Injectable } from "@nestjs/common";
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto";
import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
import { Result } from "src/common/errors/result-error.factory";

@Injectable()
export class SchedulePresetUpdateService {
    constructor(
        private readonly prisma: PrismaPostgresService,
        private readonly typeResolver: BankCodesResolver,
    ) { }

    async updatePreset(
        dto: SchedulePresetsDto
    ): Promise<Result<boolean, string>> {
        const existing = await this.prisma.schedulePresets.findFirst({
            where: { id: dto.id },
            select: {
                id: true,
                shifts: true,
            },
        });
        if (!existing) return { success: false, error: `SCHEDULE_PRESET_NOT_FOUND` };
        const normalized_shifts = dto.shifts.map((shift) => ({
            ...shift,
            start: toDateFromHHmm(shift.start_time),
            end: toDateFromHHmm(shift.end_time),
        }));

        for (const preset_shifts of normalized_shifts) {
            for (const other_shifts of normalized_shifts) {
                if (preset_shifts === other_shifts) continue;
                if (preset_shifts.week_day !== other_shifts.week_day) continue;
                const has_overlap = overlaps(
                    { start: preset_shifts.start, end: preset_shifts.end },
                    { start: other_shifts.start, end: other_shifts.end },
                )
                if (has_overlap) return { success: false, error: 'SCHEDULE_PRESET_OVERLAP' };
            }
        }
        const bank_code_results = await Promise.all(dto.shifts.map((shift) =>
            this.typeResolver.findBankCodeIDByType(shift.type),
        ));
        for (const result of bank_code_results) {
            if (!result.success) return { success: false, error: 'INVALID_SCHEDULE_PRESET' }
        }

        await this.prisma.$transaction(async (tx) => {
            await tx.schedulePresetShifts.deleteMany({ where: { preset_id: existing.id } });

            await tx.schedulePresets.update({
                where: { id: existing.id },
                data: {
                    name: dto.name,
                    shifts: {
                        create: dto.shifts.map((shift, index) => {
                            const result = bank_code_results[index] as { success: true, data: number };
                            return {
                                week_day: shift.week_day,
                                start_time: toDateFromHHmm(shift.start_time),
                                end_time: toDateFromHHmm(shift.end_time),
                                is_remote: shift.is_remote ?? false,
                                bank_code: {
                                    connect: { id: result.data },
                                },
                            }
                        }),
                    },
                },
            });
        });
        return { success: true, data: true };
    }

}