import { Shift, ShiftTimeSlot } from '../../../business/models/shiftManagement/shift';
import { ShiftAssignedDay, ShiftAssignedDayForCreation } from '../../../business/models/shiftManagement/shiftAssignedDay';
import { ShiftAssignedShift, ShiftAssignedShiftForCreation } from '../../../business/models/shiftManagement/shiftAssignedShift';
import { ShiftAssignedTimeSlot, ShiftAssignedTimeSlotForCreation } from '../../../business/models/shiftManagement/shiftAssignedTimeSlot';
import { ShiftAssignedShiftType } from '../../../business/types/shiftManagement/assignedShiftType';
import { ShiftDAO } from '../../dataAccessObjects/shiftManagement/shift';
import { ShiftAssignedDayDAO } from '../../dataAccessObjects/shiftManagement/shiftAssignedDay';
import { ShiftAssignedShiftDAO } from '../../dataAccessObjects/shiftManagement/shiftAssignedShifts';
import { ShiftAssignedTimeSlotDAO } from '../../dataAccessObjects/shiftManagement/shiftAssignedTimeSlot';
import { ShiftTimeSlotDAO } from '../../dataAccessObjects/shiftManagement/shiftTimeSlot';

export const mapShiftAssignedDayDAOToModel = (shiftAssignedDay: ShiftAssignedDayDAO): ShiftAssignedDay => {
    return {
        createdAt: shiftAssignedDay.createdAt,
        dateString: shiftAssignedDay.dateString,
        id: shiftAssignedDay.id,
        instanceId: shiftAssignedDay.instanceId,
        isWorkday: isWorkday(shiftAssignedDay.shiftAssociations),
        shiftAssociations: shiftAssignedDay.shiftAssociations
            ? shiftAssignedDay.shiftAssociations.map((shift) => mapShiftAssignedShiftDAOToModel(shift))
            : [],
        status: shiftAssignedDay.status,
        updatedAt: shiftAssignedDay.updatedAt,
        userId: shiftAssignedDay.userId,
    };
};

export const mapShiftAssignedDayModelToDAO = (shiftAssignedDay: ShiftAssignedDay | ShiftAssignedDayForCreation): ShiftAssignedDayDAO => {
    const shiftAssignedDayDAO = new ShiftAssignedDayDAO({
        dateString: shiftAssignedDay.dateString,
        instanceId: shiftAssignedDay.instanceId,
        shiftAssociations: shiftAssignedDay.shiftAssociations
            ? shiftAssignedDay.shiftAssociations.map((shift) => mapShiftAssignedShiftModelToDAO(shift))
            : [],
        status: shiftAssignedDay.status,
        userId: shiftAssignedDay.userId,
    });
    if (shiftAssignedDay instanceof ShiftAssignedDay) {
        shiftAssignedDayDAO.id = shiftAssignedDay.id;
        shiftAssignedDayDAO.isNewRecord = false;
        shiftAssignedDayDAO.createdAt = shiftAssignedDay.createdAt;
        shiftAssignedDayDAO.updatedAt = shiftAssignedDay.updatedAt;
    }
    return shiftAssignedDayDAO;
};

export const mapShiftAssignedShiftDAOToModel = (shiftAssignedShift: ShiftAssignedShiftDAO): ShiftAssignedShift => {
    return {
        assignedDayId: shiftAssignedShift.assignedDayId,
        id: shiftAssignedShift.id,
        instanceId: shiftAssignedShift.instanceId,
        shift: shiftAssignedShift.shift ? mapShiftDAOToModel(shiftAssignedShift.shift) : undefined,
        shiftAssignedDay: shiftAssignedShift.assignedDay ? mapShiftAssignedDayDAOToModel(shiftAssignedShift.assignedDay) : undefined,
        shiftCode: shiftAssignedShift.shiftCode,
        shiftRotationDayPosition: shiftAssignedShift.shiftRotationDayPosition ?? null,
        shiftRotationId: shiftAssignedShift.shiftRotationId ?? null,
        shiftVersion: shiftAssignedShift.shiftVersion,
        source: shiftAssignedShift.source,
        status: shiftAssignedShift.status,
        timeSlots: shiftAssignedShift.timeSlots?.map((timeSlot) => mapShiftAssignedTimeSlotDAOToModel(timeSlot)),
        type: shiftAssignedShift.type,
    };
};

export const mapShiftDAOToModel = (shift: ShiftDAO, timeSlots?: ShiftTimeSlotDAO[]): Shift => {
    return {
        code: shift.code,
        color: shift.color,
        description: shift.description,
        id: shift.id,
        instanceId: shift.instanceId,
        isRest: shift.isRest,
        isTemplate: shift.isTemplate,
        lastVersion: shift.lastVersion,
        name: shift.name,
        timeSlots: timeSlots
            ? timeSlots.map((timeSlot) => mapShiftTimeSlotDAOToModel(timeSlot))
            : shift.timeSlots.map((timeSlot) => mapShiftTimeSlotDAOToModel(timeSlot)),
        version: shift.version,
    };
};

export const mapShiftAssignedTimeSlotDAOToModel = (timeSlot: ShiftAssignedTimeSlotDAO): ShiftAssignedTimeSlot => {
    return {
        assignedShiftId: timeSlot.assignedShiftId,
        endTime: timeSlot.endTime,
        id: timeSlot.id,
        startTime: timeSlot.startTime,
    };
};

export const mapShiftAssignedTimeSlotModelToDAO = (timeSlot: ShiftAssignedTimeSlot | ShiftAssignedTimeSlotForCreation): ShiftAssignedTimeSlotDAO => {
    const timeSlotDAO = new ShiftAssignedTimeSlotDAO({
        assignedShiftId: timeSlot.assignedShiftId,
        endTime: timeSlot.endTime,
        startTime: timeSlot.startTime,
    });
    if (timeSlot instanceof ShiftAssignedTimeSlot) {
        timeSlotDAO.id = timeSlot.id;
        timeSlotDAO.isNewRecord = false;
    }
    return timeSlotDAO;
};

export const mapShiftAssignedShiftModelToDAO = (shift: ShiftAssignedShift | ShiftAssignedShiftForCreation): ShiftAssignedShiftDAO => {
    const shiftDAO = new ShiftAssignedShiftDAO({
        assignedDayId: shift.assignedDayId,
        instanceId: shift.instanceId,
        shiftCode: shift.shiftCode,
        shiftRotationDayPosition: shift.shiftRotationDayPosition,
        shiftRotationId: shift.shiftRotationId,
        shiftVersion: shift.shiftVersion,
        source: shift.source,
        status: shift.status,
        timeSlots: shift.timeSlots?.map((timeSlot) => mapShiftAssignedTimeSlotModelToDAO(timeSlot)),
        type: shift.type,
    });
    if (shift instanceof ShiftAssignedShift) {
        shiftDAO.id = shift.id;
        shiftDAO.isNewRecord = false;
    }
    return shiftDAO;
};

export const mapShiftTimeSlotDAOToModel = (timeSlot: ShiftTimeSlotDAO): ShiftTimeSlot => {
    return {
        endTime: timeSlot.endTime,
        id: timeSlot.id,
        instanceId: timeSlot.instanceId,
        startTime: timeSlot.startTime,
    };
};

export const isWorkday = (shiftAssociations?: ShiftAssignedShiftDAO[]): boolean => {
    return !!(
        shiftAssociations &&
        shiftAssociations.length > 0 &&
        shiftAssociations.some((shiftAssociation) => shiftAssociation.type === ShiftAssignedShiftType.WORK)
    );
};
