import { BaseAdapter } from '@humand-packages/common';
import { Service } from 'typedi';
import { PortsDI } from '../../../../config/portsDI';
import { Instance } from '../../../instances/business/models/instance';
import { DaySummaryScheduleSource, TimeOffDaySummary, TimeTrackingDaySummaryPort } from '../../../timeOff/business/ports/timeTrackingDaySummaryPort';
import TimeTrackingService from '../../business/services/timeTracking';
import { DaySummaryScheduleSource as TimeTrackingDaySummaryScheduleSourceEnum } from '../../business/types/scheduleSource';

/**
 * Maps timeTracking's DaySummaryScheduleSource enum to the port's union type.
 *
 * The exhaustive switch is intentional: if a new value is added to the source
 * enum and not mirrored in the port's DaySummaryScheduleSource const, the
 * `_exhaustive: never` assignment below produces a compile error, forcing the
 * adapter and the port to be updated in lockstep. The runtime throw is a
 * defense-in-depth in case an untyped value sneaks through.
 */
const mapScheduleSource = (source: TimeTrackingDaySummaryScheduleSourceEnum): DaySummaryScheduleSource => {
    switch (source) {
        case TimeTrackingDaySummaryScheduleSourceEnum.NO_SCHEDULE:
            return DaySummaryScheduleSource.NO_SCHEDULE;
        case TimeTrackingDaySummaryScheduleSourceEnum.WORK_SCHEDULE:
            return DaySummaryScheduleSource.WORK_SCHEDULE;
        case TimeTrackingDaySummaryScheduleSourceEnum.SHIFT:
            return DaySummaryScheduleSource.SHIFT;
        default: {
            const _exhaustive: never = source;
            throw new Error(`Unhandled DaySummaryScheduleSource value: ${String(_exhaustive)}`);
        }
    }
};

@Service()
export class TimeTrackingDaySummaryAdapter extends BaseAdapter implements TimeTrackingDaySummaryPort {
    constructor(@PortsDI(TimeTrackingService) private readonly timeTrackingService: TimeTrackingService) {
        super();
    }

    async getOrCreateDaySummariesByUser(
        userId: number,
        instance: Instance,
        fromDate: string,
        toDate: string,
        includeEntries: boolean,
    ): Promise<TimeOffDaySummary[]> {
        const summaries = await this.timeTrackingService.getOrCreateDaySummariesByUser(userId, instance, fromDate, toDate, includeEntries);
        return summaries.map((s) => ({
            dateString: s.dateString,
            scheduledHours: s.scheduledHours,
            isWorkday: s.isWorkday,
            scheduleSource: mapScheduleSource(s.scheduleSource),
            holidays: s.holidays?.map((h) => ({ id: h.id })),
        }));
    }
}
