"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractGTFSTripRunManager = void 0;
const DateTimeUtils_1 = require("../../../../../../helpers/DateTimeUtils");
const CoreToken_1 = require("@golemio/core/dist/helpers/ioc/CoreToken");
const ioc_1 = require("@golemio/core/dist/integration-engine/ioc");
const VPUtils_1 = require("../VPUtils");
class AbstractGTFSTripRunManager {
    constructor(positionsRepository, tripsRepository, runsRepository, runTripsRedisRepository, testMode = false) {
        this.positionsRepository = positionsRepository;
        this.tripsRepository = tripsRepository;
        this.runsRepository = runsRepository;
        this.runTripsRedisRepository = runTripsRedisRepository;
        this.testMode = testMode;
        this.CURRENT_TRIP_START_TIME_WINDOW_IN_MS = 60 * 60 * 1000; // 1 hour
        this.setAndReturnScheduledTrips = async (scheduleData) => {
            const { route_id, run_number, msg_last_timestamp } = scheduleData;
            const scheduledTripIds = await this.runTripsRedisRepository.get(`${route_id}_${run_number}`);
            if (scheduledTripIds?.schedule) {
                return scheduledTripIds.schedule;
            }
            const scheduledTrips = await this.runsRepository.getScheduledTrips(route_id, run_number, msg_last_timestamp);
            for (let index = 0; index < scheduledTrips.length; index++) {
                const trip = scheduledTrips[index];
                trip.start_timestamp = DateTimeUtils_1.DateTimeUtils.formatSQLTimestamp(trip.start_timestamp);
                trip.end_timestamp = DateTimeUtils_1.DateTimeUtils.formatSQLTimestamp(trip.end_timestamp);
                trip.requiredTurnaroundSeconds = this.isSameStop(trip, scheduledTrips, index) ? 0 : this.turnaroundEstimateInSeconds;
            }
            await this.runTripsRedisRepository.set(`${route_id}_${run_number}`, { schedule: scheduledTrips }, undefined, VPUtils_1.VPUtils.getNextExpireTimestamp());
            return scheduledTrips;
        };
        this.isSameStop = (trip, scheduledTrips, index) => {
            if (index === 0) {
                return true;
            }
            return trip.first_stop_id === scheduledTrips[index - 1].last_stop_id;
        };
        this.config = ioc_1.IntegrationEngineContainer.resolve(CoreToken_1.CoreToken.SimpleConfig);
        this.logger = ioc_1.IntegrationEngineContainer.resolve(CoreToken_1.CoreToken.Logger);
        this.turnaroundEstimateInSeconds = this.config.getValue("module.pid.vehicle-positions.gtfsTripRun.turnaroundEstimateInSeconds", 0);
    }
    determineCurrentTripFromTimestamp(schedule, timestampScheduled) {
        let currentTrip = undefined;
        for (const tripCache of schedule) {
            const startTimestamp = new Date(tripCache.start_timestamp);
            const endTimestamp = new Date(tripCache.end_timestamp);
            if (!timestampScheduled.isBetween(startTimestamp, endTimestamp, "second", "[]")) {
                continue;
            }
            if (!currentTrip || startTimestamp.getTime() > new Date(currentTrip.start_timestamp).getTime()) {
                currentTrip = tripCache;
            }
        }
        return currentTrip;
    }
    determineCurrentTripFromTripId(schedule, gtfsTripId) {
        let currentTrip = undefined;
        if (!gtfsTripId) {
            return currentTrip;
        }
        for (const tripCache of schedule) {
            if (tripCache.trip_id !== gtfsTripId) {
                continue;
            }
            currentTrip = tripCache;
            break;
        }
        // if the current trip is too far in the future, ignore it
        if (currentTrip?.start_timestamp) {
            const tripStartTimestamp = new Date(currentTrip.start_timestamp);
            const now = new Date();
            const diff = tripStartTimestamp.getTime() - now.getTime();
            if (diff > this.CURRENT_TRIP_START_TIME_WINDOW_IN_MS) {
                currentTrip = undefined;
            }
        }
        return currentTrip;
    }
    /**
     * Get scheduled trips adjacent to run message timestamp (scheduled)
     *   originally based on route id and run number
     */
    getAdjacentTrips(schedule, timestampScheduled, currentTripId) {
        return schedule.filter((scheduledTrip) => scheduledTrip.trip_id !== currentTripId && this.isTripAdjacent(scheduledTrip, timestampScheduled.valueOf()));
    }
    isTripAdjacent(scheduledTrip, messageScheduledTimestamp) {
        const { startTimeWindowInMinutes, endTimeWindowInMinutes } = this.getAdjacentTripTimeWindow();
        const startTimestamp = new Date(scheduledTrip.start_timestamp).getTime();
        const endTimestamp = new Date(scheduledTrip.end_timestamp).getTime();
        const leftBound = messageScheduledTimestamp - endTimeWindowInMinutes * 60 * 1000;
        const rightBound = messageScheduledTimestamp + startTimeWindowInMinutes * 60 * 1000;
        return ((leftBound <= endTimestamp && endTimestamp <= messageScheduledTimestamp) ||
            (rightBound >= startTimestamp && startTimestamp >= messageScheduledTimestamp));
    }
}
exports.AbstractGTFSTripRunManager = AbstractGTFSTripRunManager;
//# sourceMappingURL=AbstractGTFSTripRunManager.js.map