"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SkipHelper = void 0;
const RouteTypeEnums_1 = require("../../../../helpers/RouteTypeEnums");
const RunHelper_1 = require("./RunHelper");
const const_1 = require("./const");
/** Extracts the last numeric sequence from strings like:
 * Os 1111 -> 1111
 * Os 1111 B -> 1111
 * Rx 1/1111 A -> 1111
 */
const TRIP_NUMBER_REGEX = /(\d+)(?!.*\d)/;
class SkipHelper {
    /**
     * Used exclusively in transfer boards to skip transfers for the current trip
     * (i.e., transfers within the vehicle where the transfer board is located)
     */
    static isMatchingTripNumber(departure, tripNumber) {
        const tripShortName = departure.trip_short_name;
        if (!tripShortName) {
            return false;
        }
        const lastNumber = tripShortName.match(TRIP_NUMBER_REGEX)?.[1];
        return !!lastNumber && lastNumber === tripNumber;
    }
    static hasNoDelayInfo(departure) {
        if (!("arrival_datetime" in departure)) {
            return true;
        }
        const statePosition = departure["trip.last_position.state_position"];
        const isFinished = statePosition === "after_track" || statePosition === "after_track_delayed";
        return !departure.is_delay_available || isFinished;
    }
    /**
     * Used exclusively in departure boards when skip[]=missing is requested (without untracked)
     */
    static isVehicleMissing(departure, runScheduleMap, untrackedTrips, nowDate = new Date()) {
        // Not missing if essential trip data is missing or if delay information is available
        if (!("trip.start_timestamp" in departure) ||
            departure.run_number === null ||
            departure.route_id === null ||
            departure.is_delay_available) {
            return false;
        }
        // Use fallback to planned_start_timestamp if trip.start_timestamp is null
        const rawStartTimestamp = departure["trip.start_timestamp"] ?? departure.planned_start_timestamp;
        if (!rawStartTimestamp) {
            return false;
        }
        const startTimestamp = new Date(rawStartTimestamp);
        const minutesToStart = (startTimestamp.getTime() - nowDate.getTime()) / 60000;
        /// Not missing if departure is too far in the future (threshold varies for metro)
        if (this.isOutsideStartThreshold(minutesToStart, departure.route_type)) {
            return false;
        }
        // Missing if the trip should have already started
        else if (this.hasAlreadyDeparted(minutesToStart)) {
            return true;
        }
        // Cannot determine missing status without run schedule information
        const runSchedule = runScheduleMap?.get(RunHelper_1.RunHelper.composeRunId(departure.route_id, departure.run_number));
        if (!runSchedule) {
            return false;
        }
        // Not missing if this is the first trip in the run or if trip isn't found
        const runTripIndex = runSchedule.findIndex((trip) => trip.trip_id === departure.trip_id);
        if (runTripIndex === -1 || runTripIndex === 0) {
            return false;
        }
        // Not missing if there's a significant gap after the previous trip
        const previousRunTripEnd = new Date(runSchedule[runTripIndex - 1].end_timestamp);
        if (this.hasLargeTimegapBetweenTrips(previousRunTripEnd, startTimestamp)) {
            return false;
        }
        // Not missing if the previous trip has delay information available
        const isPreviousUntracked = untrackedTrips?.has(runSchedule[runTripIndex - 1].trip_id);
        if (!isPreviousUntracked) {
            return false;
        }
        const previousStartTimestamp = new Date(runSchedule[runTripIndex - 1].start_timestamp);
        const previousMinutesToStart = (previousStartTimestamp.getTime() - nowDate.getTime()) / 60000;
        // Missing if previous trip should have already started
        if (this.hasAlreadyDeparted(previousMinutesToStart)) {
            return true;
        }
        // Check position of previous trip in the run
        const previousRunTripIndex = runTripIndex - 1;
        if (previousRunTripIndex === -1 || previousRunTripIndex === 0) {
            return false;
        }
        // Check for gaps before the previous trip
        const previousPreviousRunTripEnd = new Date(runSchedule[previousRunTripIndex - 1].end_timestamp);
        if (this.hasLargeTimegapBetweenTrips(previousPreviousRunTripEnd, previousStartTimestamp)) {
            return false;
        }
        // If we reach here, the previous untracked trip is likely missing,
        // which implies the current trip is also missing
        return true;
    }
    static isTripCanceled(departure) {
        return !!departure.is_canceled;
    }
    static isVehicleAtStop(departure) {
        if (!("arrival_datetime" in departure)) {
            return false;
        }
        const statePosition = departure["trip.last_position.state_position"];
        const isAtStop = departure.stop_sequence === departure["trip.last_position.this_stop_sequence"];
        const isPassStop = !!departure["trip.last_position.last_stop_sequence"] &&
            departure.stop_sequence <= departure["trip.last_position.last_stop_sequence"];
        const isFinished = statePosition === "after_track" || statePosition === "after_track_delayed";
        return isAtStop || isPassStop || isFinished;
    }
    static isOutsideStartThreshold(minutesToStart, routeType) {
        const isMetro = routeType === RouteTypeEnums_1.GTFSRouteTypeEnum.METRO;
        return isMetro ? minutesToStart >= const_1.START_SOON_METRO_MINUTES_THRESHOLD : minutesToStart >= const_1.START_SOON_MINUTES_THRESHOLD;
    }
    static hasAlreadyDeparted(minutesToStart) {
        return minutesToStart < const_1.DEPARTURED_MINUTES_THRESHOLD;
    }
    static hasLargeTimegapBetweenTrips(endTimestamp, startTimestamp) {
        const minutesAfterPrevious = (startTimestamp.getTime() - endTimestamp.getTime()) / 60000;
        return minutesAfterPrevious >= const_1.TRIP_GAP_MINUTES_THRESHOLD;
    }
}
exports.SkipHelper = SkipHelper;
//# sourceMappingURL=SkipHelper.js.map