import { LoggerPort } from '@humand-packages/common';
import { Service } from 'typedi';
import { PortsDI } from '../../../../../config/portsDI';
import { RealTimeNotificationsService } from '../../../../../services/realTimeNotifications';
import { TimeTrackingCategorizedHourApprovalStepState } from '../../../infrastructure/constants/timeTracking/categorizedHourApprovalStepStates';
import { TimeTrackingHourCategorizationRepositoryPort } from '../../../infrastructure/ports/timeTracking/timeTrackingHourCategorizationRepositoryPort';
import TimeTrackingNotificationsPort from '../../ports/timeTrackingNotificationsPort';
import { TimeTrackingCategorizedHourApprovalService } from './timeTrackingCategorizedHourApprovalService';

@Service()
export class TimeTrackingCategorizedHourNotificationsService {
    constructor(
        private readonly realTimeNotificationsService: RealTimeNotificationsService,
        private readonly approvalService: TimeTrackingCategorizedHourApprovalService,
        @PortsDI(TimeTrackingHourCategorizationRepositoryPort)
        private readonly hourCategorizationRepository: TimeTrackingHourCategorizationRepositoryPort,
        @PortsDI(TimeTrackingNotificationsPort)
        private readonly notificationsPort: TimeTrackingNotificationsPort,
        private readonly logger: LoggerPort,
    ) {}

    public notifyCategorizedHourStepReviewed = async (instanceId: number, categorizedHourId: string, reviewedStepId: string): Promise<void> => {
        const [categorizedHour, steps] = await Promise.all([
            this.hourCategorizationRepository.getCategorizedHour(instanceId, categorizedHourId),
            this.approvalService.getCategorizedHourApprovalSteps(instanceId, categorizedHourId),
        ]);

        if (!categorizedHour) return;

        const reviewedStep = steps.find((s) => s.id === reviewedStepId);
        if (!reviewedStep) return;

        const nextStep = steps.find((s) => s.position > reviewedStep.position);
        const recipientSteps = nextStep ? [reviewedStep, nextStep] : [reviewedStep];
        const userIds = [...new Set(recipientSteps.flatMap((step) => step.potentialApprovers.map((pa) => pa.userId)))];

        this.realTimeNotificationsService.emitCategorizedHourStatusUpdatedEvent(
            instanceId,
            categorizedHourId,
            categorizedHour.status,
            steps.map((step) => ({
                potentialApproverIds: step.potentialApprovers.map((pa) => pa.userId),
                status: step.state,
                stepId: step.id,
            })),
            userIds,
        );

        if (nextStep && nextStep.state === TimeTrackingCategorizedHourApprovalStepState.PENDING) {
            await this.notificationsPort
                .notifyCategorizedHourStepPending(instanceId, categorizedHourId, nextStep.id)
                .catch((err) => this.logger.error('Failed to notify step pending', { err, categorizedHourId }));
        }
    };
}
