"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropagateDelayTask = void 0;
const RouteTypeEnums_1 = require("../../../../../helpers/RouteTypeEnums");
const RunTripsRedisRepository_1 = require("../../../../ropid-gtfs/data-access/cache/RunTripsRedisRepository");
const helpers_1 = require("@golemio/core/dist/integration-engine/helpers");
const QueueManager_1 = require("@golemio/core/dist/integration-engine/queueprocessors/QueueManager");
const const_1 = require("../../../../../const");
const PropagateDelaySchema_1 = require("../schema/PropagateDelaySchema");
const AbstractPropagateDelayTask_1 = require("./abstract/AbstractPropagateDelayTask");
const ALLOWED_PROPAGATION_STATES = [const_1.StatePositionEnum.ON_TRACK, const_1.StatePositionEnum.AT_STOP, const_1.StatePositionEnum.AFTER_TRACK_DELAYED];
class PropagateDelayTask extends AbstractPropagateDelayTask_1.AbstractPropagateDelayTask {
    constructor(queuePrefix) {
        super(queuePrefix);
        this.queueName = "propagateDelay";
        this.queueTtl = 5 * 60 * 1000; // 5 minutes
        this.schema = PropagateDelaySchema_1.PropagateDelayValidationSchema;
        this.mapDelayedPositionsToRunTrips = (processedPositions, updatedTrips) => {
            const tripPositionMap = [];
            const trainTripPositionMap = [];
            for (const batch of processedPositions) {
                const statePosition = batch.context.lastPositionState;
                if (!statePosition || !ALLOWED_PROPAGATION_STATES.includes(statePosition)) {
                    continue;
                }
                const delayInSeconds = batch.context.lastPositionDelay;
                const originUnixTimestamp = batch.context.lastPositionOriginTimestamp;
                if (typeof delayInSeconds !== "number" || typeof originUnixTimestamp !== "number") {
                    continue;
                }
                const trip = updatedTrips.find((el) => el.id === batch.context.tripId);
                if (trip && this.isUpdateDelayRunTripsIdsData(trip)) {
                    tripPositionMap.push({
                        position: {
                            delayInSeconds,
                            originTimestamp: new Date(originUnixTimestamp),
                            bearing: batch.context.lastPositionTracking?.properties.bearing,
                            originId: batch.context.lastPositionId,
                        },
                        trip: trip,
                    });
                }
                else if (trip && this.isBlockedTrainTripData(trip)) {
                    trainTripPositionMap.push({
                        position: {
                            delayInSeconds,
                            originTimestamp: new Date(originUnixTimestamp),
                            bearing: batch.context.lastPositionTracking?.properties.bearing,
                            originId: batch.context.lastPositionId,
                        },
                        trip: trip,
                    });
                }
            }
            return { tripPositionMap, trainTripPositionMap };
        };
        this.isUpdateDelayRunTripsIdsData = (data) => {
            const { internal_route_name, internal_run_number, gtfs_trip_id, vehicle_registration_number } = data;
            return !!(internal_route_name &&
                internal_run_number &&
                gtfs_trip_id &&
                typeof vehicle_registration_number !== "undefined");
        };
        this.isBlockedTrainTripData = (data) => {
            const { gtfs_trip_id, gtfs_block_id, gtfs_route_type } = data;
            return !!(gtfs_trip_id && gtfs_block_id && gtfs_route_type === RouteTypeEnums_1.GTFSRouteTypeEnum.TRAIN);
        };
        this.runTripsRedisRepository = new RunTripsRedisRepository_1.RunTripsRedisRepository();
    }
    async execute(data) {
        const { tripPositionMap, trainTripPositionMap } = this.mapDelayedPositionsToRunTrips(data.processedPositions, data.trips);
        if (trainTripPositionMap.length > 0) {
            await QueueManager_1.QueueManager.sendMessageToExchange(this.queuePrefix, "propagateTrainDelay", {
                data: trainTripPositionMap,
            });
        }
        for (const delayedPositions of tripPositionMap) {
            const { internal_route_name, internal_run_number, gtfs_trip_id, gtfs_block_id, vehicle_registration_number, start_timestamp, } = delayedPositions.trip;
            const scheduledTrips = await this.runTripsRedisRepository.get(`${internal_route_name}_${internal_run_number}`);
            const positionTripWeekDay = new Date(start_timestamp).getDay();
            const gtfsCurrentTrip = scheduledTrips?.schedule.find((trip) => {
                return this.isCurrentGtfsTrip(trip, gtfs_trip_id, positionTripWeekDay);
            });
            if (!gtfsCurrentTrip) {
                helpers_1.log.info(`${this.queueName}: could not determine GTFS trip from run trips data: ` +
                    JSON.stringify(delayedPositions.trip).substring(0, 2000));
                continue;
            }
            const gtfsNextTrips = scheduledTrips.schedule.filter((trip) => {
                return this.isConnectingLinkIn60Minutes(gtfsCurrentTrip, trip);
            });
            try {
                await this.propagateDelayForGtfsTrip({
                    currentGtfsTripId: gtfs_trip_id,
                    currentGtfsBlockId: gtfs_block_id ?? null,
                    currentOriginTimestamp: delayedPositions.position.originTimestamp,
                    currentDelay: delayedPositions.position.delayInSeconds,
                    currentRegistrationNumber: vehicle_registration_number,
                    currentStartTime: gtfsCurrentTrip.start_timestamp,
                    currentEndTime: gtfsCurrentTrip.end_timestamp,
                    currentBearing: delayedPositions.position.bearing,
                    nextGtfsTrips: gtfsNextTrips.map((trip) => {
                        return {
                            trip_id: trip.trip_id,
                            requiredTurnaroundSeconds: trip.requiredTurnaroundSeconds,
                        };
                    }),
                    originPositionId: delayedPositions.position.originId,
                });
            }
            catch (err) {
                helpers_1.log.warn(`${this.queueName}: could not propagate delay for GTFS trip: ${gtfs_trip_id} - ${err.message}`);
            }
        }
    }
    isConnectingLinkIn60Minutes(gtfsCurrentTrip, trip) {
        const currentTripEndTime = new Date(gtfsCurrentTrip.end_timestamp);
        const nextTripStartTime = new Date(trip.start_timestamp);
        const currentTripEndTimePlus60Minutes = new Date(currentTripEndTime.getTime() + 60 * 60 * 1000);
        return currentTripEndTimePlus60Minutes >= nextTripStartTime && currentTripEndTime <= nextTripStartTime;
    }
    isCurrentGtfsTrip(tripSchedule, propagatedGtfsTripId, propagatedTripWeekDay) {
        const tripWeekDay = new Date(tripSchedule.start_timestamp).getDay();
        return tripSchedule.trip_id === propagatedGtfsTripId && tripWeekDay === propagatedTripWeekDay;
    }
}
exports.PropagateDelayTask = PropagateDelayTask;
//# sourceMappingURL=PropagateDelayTask.js.map