import { ErrorCodes, IllegalStateError, SerializationClass } from '@humand-packages/common';
import { ShiftRotationDayType } from '../../../business/enum/shiftManagement/shiftRotationDayType';
import { Shift } from '../../../business/models/shiftManagement/shift';
import { ShiftRotation, ShiftRotationDay, ShiftRotationDayShift } from '../../../business/models/shiftManagement/shiftRotation';

/** Shared identity + metadata fields for any rotation DTO (full, list, ...). */
export interface ShiftRotationHeaderDTO {
    id: string;
    name: string;
    description: string | null;
    createdAt: string;
    updatedAt: string;
}

export interface TimeSlotDTO {
    startTime: string;
    endTime: string;
}

export interface ShiftRotationDayShiftDTO {
    shiftCode: string;
    name: string | null;
    color: string | null;
    description: string | null;
    timeSlots: TimeSlotDTO[];
}

export interface ShiftRotationDayDTO {
    type: ShiftRotationDayType;
    shifts: ShiftRotationDayShiftDTO[];
}

export interface ShiftRotationDTO extends ShiftRotationHeaderDTO {
    days: ShiftRotationDayDTO[];
}

interface ShiftRotationSCExtraData {
    shiftsByCode: Map<string, Shift>;
}

export class ShiftRotationSC extends SerializationClass<ShiftRotation, ShiftRotationDTO, ShiftRotationSCExtraData> {
    serialize(entity: ShiftRotation, extraData: ShiftRotationSCExtraData): ShiftRotationDTO {
        return {
            createdAt: entity.createdAt.toISOString(),
            days: entity.days.map((day) => this.serializeDay(day, extraData.shiftsByCode)),
            description: entity.description,
            id: entity.id,
            name: entity.name,
            updatedAt: entity.updatedAt.toISOString(),
        };
    }

    private serializeDay = (day: ShiftRotationDay, shiftsByCode: Map<string, Shift>): ShiftRotationDayDTO => ({
        shifts: day.shifts.map((s) => this.serializeDayShift(s, shiftsByCode)),
        type: day.type,
    });

    private serializeDayShift = (s: ShiftRotationDayShift, shiftsByCode: Map<string, Shift>): ShiftRotationDayShiftDTO => {
        const shift = shiftsByCode.get(s.shiftCode);
        if (!shift) {
            throw new IllegalStateError(`Rotation references missing Shift for code ${s.shiftCode}`, ErrorCodes.ILLEGAL_STATE);
        }
        return {
            color: shift.color,
            description: shift.description,
            name: shift.name,
            shiftCode: s.shiftCode,
            timeSlots: shift.timeSlots.map((t) => ({ endTime: t.endTime, startTime: t.startTime })),
        };
    };
}
