import { TimeSlot } from '../../business/models/timeTracking/scheduleData';
import { AssignedWorkSchedule, WorkSchedule, WorkScheduleUser, WorkScheduleUserAssignment } from '../../business/models/workSchedule';
import { WorkScheduleUserAssignmentType } from '../../business/types/workScheduleUserAssignment';
import { WORK_SCHEDULE_ASSIGNMENT_TYPE } from '../constants/workScheduleUserAssignment';
import { ScheduledDaysDAO } from '../dataAccessObjects/scheduledDays';
import { TimeSlotDAO } from '../dataAccessObjects/timeSlots';
import { WorkScheduleDAO } from '../dataAccessObjects/workSchedule';
import { WorkScheduleUsersDAO } from '../dataAccessObjects/workScheduleUsers';

export const mapDAOsToWorkSchedule = (
    createdSchedule: WorkScheduleDAO,
    createdDays: ScheduledDaysDAO[],
    createdSlots: never[] | TimeSlotDAO[],
): WorkSchedule => {
    const scheduledDays = createdDays.map((day) => ({
        dayOfWeek: day.dayOfWeek,
        timeSlots: createdSlots.filter((slot) => slot.scheduledDayId === day.id).map(mapTimeSlotDaoToModel),
    }));
    return {
        autoCreated: createdSchedule.autoCreated,
        code: createdSchedule.code,
        collaborators: [],
        createdAt: createdSchedule.createdAt,
        createdBy: createdSchedule.createdBy,
        deletedAt: createdSchedule.deletedAt ?? undefined,
        description: createdSchedule.description,
        generalTimeSlots: createdSchedule.generalTimeSlots && scheduledDays.length ? scheduledDays[0]?.timeSlots : [],
        id: createdSchedule.id,
        instanceId: createdSchedule.instanceId,
        lastVersion: createdSchedule.lastVersion,
        name: createdSchedule.name,
        scheduledDays: scheduledDays,
        updatedAt: createdSchedule.updatedAt,
        version: createdSchedule.version,
    };
};

export const convertDAOToWorkSchedule = (schedule: WorkScheduleDAO): WorkSchedule => {
    const scheduledDays =
        schedule.scheduledDays?.map((day) => ({
            dayOfWeek: day.dayOfWeek,
            timeSlots: day.timeSlots.map(mapTimeSlotDaoToModel).sort(compareTimeSlots),
        })) ?? [];
    return {
        autoCreated: schedule.autoCreated,
        code: schedule.code,
        collaborators:
            schedule.collaborators?.map((association) => association.id) ??
            schedule.workScheduleUsers?.map((association) => association.userId) ??
            [],
        createdAt: schedule.createdAt,
        createdBy: schedule.createdBy,
        deletedAt: schedule.deletedAt ?? undefined,
        description: schedule.description,
        generalTimeSlots: schedule.generalTimeSlots && scheduledDays.length ? scheduledDays[0]?.timeSlots : [],
        hash: schedule.hash,
        id: schedule.id,
        instanceId: schedule.instanceId,
        lastVersion: schedule.lastVersion,
        name: schedule.name,
        scheduledDays: scheduledDays,
        updatedAt: schedule.updatedAt,
        version: schedule.version,
    };
};

export const convertDAOToAssignedWorkSchedule = (schedule: WorkScheduleDAO, assignment: WorkScheduleUsersDAO): AssignedWorkSchedule => {
    const convertedSchedule = convertDAOToWorkSchedule(schedule);
    return {
        ...convertedSchedule,
        current: assignment.current,
        endDate: assignment.endDateString,
        startDate: assignment.startDateString,
        userId: assignment.userId,
    };
};

export const mapUserAssigmentWorkSchedule = (workScheduleUserAssignment: WorkScheduleUserAssignment): WorkScheduleUserAssignment => {
    return {
        ...workScheduleUserAssignment,
        assignmentType: mapPriorityToAssignmentType(workScheduleUserAssignment.assignmentTypeNumber),
    };
};

export const mapWorkScheduleUserDAOToUserAssigmentWorkSchedule = (
    schedule: WorkScheduleDAO,
    assignment: WorkScheduleUsersDAO,
    assignmentTypeNumber: number,
): WorkScheduleUserAssignment => {
    return {
        assignmentType: mapPriorityToAssignmentType(assignmentTypeNumber),
        assignmentTypeNumber,
        current: assignment.current,
        endDate: assignment.endDate ?? undefined,
        endDateString: assignment.endDateString ?? undefined,
        id: assignment.id,
        startDate: assignment.startDate,
        startDateString: assignment.startDateString,
        userId: assignment.userId,
        workScheduleId: assignment.workScheduleId,
        workScheduleVersion: schedule.version,
    };
};

function mapPriorityToAssignmentType(assignmentTypeNumber: number): WorkScheduleUserAssignmentType {
    switch (assignmentTypeNumber) {
        case WORK_SCHEDULE_ASSIGNMENT_TYPE.ACTIVE:
            return WorkScheduleUserAssignmentType.ACTIVE;
        case WORK_SCHEDULE_ASSIGNMENT_TYPE.UPCOMING:
            return WorkScheduleUserAssignmentType.UPCOMING;
        default:
            return WorkScheduleUserAssignmentType.PAST;
    }
}

export const TIME_REGEX = /(\d{1,2}:\d{1,2})/;
export function mapTimeSlotDaoToModel(slot: TimeSlotDAO): TimeSlot {
    const startTimeMatch = slot.startTime.match(TIME_REGEX);
    const endTimeMatch = slot.endTime.match(TIME_REGEX);
    return {
        endTime: endTimeMatch ? endTimeMatch[0] : slot.endTime,
        startTime: startTimeMatch ? startTimeMatch[0] : slot.startTime,
    };
}

// TODO verify this still works as expected
export function compareTimeSlots(a: TimeSlot, b: TimeSlot) {
    const startTimeComparison = a.startTime.localeCompare(b.startTime);
    if (startTimeComparison !== 0) {
        return startTimeComparison;
    } else {
        return a.endTime.localeCompare(b.endTime);
    }
}

export const mapWorkScheduleUserDAOToWorkScheduleUser = (workScheduleUser: WorkScheduleUsersDAO): WorkScheduleUser => {
    return {
        current: workScheduleUser.current,
        endDate: workScheduleUser.endDate ?? undefined,
        endDateString: workScheduleUser.endDateString,
        id: workScheduleUser.id,
        startDate: workScheduleUser.startDate,
        startDateString: workScheduleUser.startDateString,
        userId: workScheduleUser.userId,
        workScheduleId: workScheduleUser.workScheduleId,
    };
};
