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 SchedulePresetsCreateService {
    constructor(
        private readonly prisma: PrismaPostgresService,
        private readonly typeResolver: BankCodesResolver,
    ) { }
    //_________________________________________________________________
    //                              CREATE
    //_________________________________________________________________
    async createPreset(dto: SchedulePresetsDto): Promise<Result<boolean, string>> {
        try {
            //validate new unique name
            const existing = await this.prisma.schedulePresets.findFirst({
                where: { name: dto.name },
                select: { name: true },
            });
            if (existing) return { success: false, error: 'INVALID_SCHEDULE_PRESET' };

            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) {
                    //skip if same object or id week_day is not the same
                    if (preset_shifts === other_shifts) continue;
                    if (preset_shifts.week_day !== other_shifts.week_day) continue;
                    //check overlaping possibilities
                    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' };
                }
            }

            //validate bank_code_id/type and map them
            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.schedulePresets.create({
                    data: {
                        name: dto.name,
                        // is_default: dto.is_default ?? false,
                        shifts: {
                            create: dto.shifts.map((shift, index) => {
                                //validated bank_codes sent as a Result Array to access its data
                                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 uses the FK links to set the bank_code_id
                                        connect: { id: result.data },
                                    },
                                }
                            }),
                        },
                    },
                });
            });
            return { success: true, data: true }
        } catch (error) {
            return { success: false, error: 'INVALID_SCHEDULE_PRESET' }
        }
    }
}
