"use strict";
/**
 * Router /WEB LAYER/: maps routes to specific controller functions, passes request parameters and handles responses.
 * Handles web logic (http request, response). Sets response headers, handles error responses.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.v2VehiclepositionsRouter = exports.V2VehiclePositionsRouter = void 0;
const shared_1 = require("../../../shared");
const constants_1 = require("../../../shared/constants");
const data_access_1 = require("../../data-access");
const AbstractRouter_1 = require("@golemio/core/dist/helpers/routing/AbstractRouter");
const trace_provider_1 = require("@golemio/core/dist/monitoring/opentelemetry/trace-provider");
const Utils_1 = require("@golemio/core/dist/output-gateway/Utils");
const Validation_1 = require("@golemio/core/dist/output-gateway/Validation");
const ioc_1 = require("@golemio/core/dist/output-gateway/ioc");
const express_1 = require("@golemio/core/dist/shared/express");
const express_validator_1 = require("@golemio/core/dist/shared/express-validator");
const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors");
const moment_timezone_1 = __importDefault(require("@golemio/core/dist/shared/moment-timezone"));
class V2VehiclePositionsRouter extends AbstractRouter_1.AbstractRouter {
    constructor() {
        super(constants_1.RouteVersion.v2, "vehiclepositions");
        this.GetAll = async (req, res, next) => {
            const queryData = (0, express_validator_1.matchedData)(req);
            const preferredTimezone = shared_1.RopidRouterUtils.getPreferredTimezone(queryData.preferredTimezone);
            const span = (0, trace_provider_1.createChildSpan)("V2VehiclePositionsRouter.GetAll");
            try {
                const result = await this.tripWithPositionRepository.GetAll({
                    cisTripNumber: Number(queryData.cisTripNumber) || undefined,
                    includeNotTracking: (0, Utils_1.parseBooleanQueryParam)(queryData.includeNotTracking),
                    includeNotPublic: (0, Utils_1.parseBooleanQueryParam)(queryData.includeNotPublic),
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                    routeId: queryData.routeId,
                    routeShortName: queryData.routeShortName,
                    updatedSince: queryData.updatedSince ? new Date(queryData.updatedSince) : null,
                    preferredTimezone,
                });
                res.set("X-Last-Modified", (0, moment_timezone_1.default)(result.metadata.maxUpdatedAt).toISOString()).status(200).send(result.data);
            }
            catch (err) {
                next(err);
            }
            finally {
                span?.end();
            }
        };
        this.GetOne = async (req, res, next) => {
            const queryData = (0, express_validator_1.matchedData)(req);
            const id = req.params.id;
            const preferredTimezone = shared_1.RopidRouterUtils.getPreferredTimezone(queryData.preferredTimezone);
            try {
                const data = await this.tripWithPositionRepository.GetOneByGTFSTripId(id, {
                    includeNotTracking: (0, Utils_1.parseBooleanQueryParam)(queryData.includeNotTracking),
                    includePositions: (0, Utils_1.parseBooleanQueryParam)(queryData.includePositions),
                    preferredTimezone,
                });
                if (!data) {
                    throw new golemio_errors_1.GeneralError("not_found", this.constructor.name, undefined, 404);
                }
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetGtfsRtFeed = (fileName, sendAsJson = false) => {
            return async (_req, res, next) => {
                try {
                    let file = null;
                    let timestamp = null;
                    try {
                        const connection = this.redisConnector.getConnection();
                        const result = await Promise.all([
                            connection.hget("files:gtfsRt", fileName + ".pb"),
                            connection.get("files:gtfsRt:" + fileName + "_timestamp"),
                        ]);
                        file = result[0];
                        timestamp = result[1];
                    }
                    catch (err) {
                        throw new golemio_errors_1.GeneralError("Error while fetching GTFS-RT feed", this.constructor.name, err, 500);
                    }
                    if (!file) {
                        throw new golemio_errors_1.GeneralError("GTFS-RT feed not found", this.constructor.name, undefined, 404);
                    }
                    res.setHeader("Last-Modified", new Date(timestamp ? parseInt(timestamp) * 1000 : 0).toISOString());
                    res.setHeader("Content-Type", sendAsJson ? "application/json" : "application/octet-stream");
                    res.status(200).send(sendAsJson ? file : Buffer.from(file, "binary"));
                }
                catch (err) {
                    next(err);
                }
            };
        };
        /**
         * Initiates all routes. Should respond with correct data to a HTTP requests to all routes.
         * @param {number|string} expire TTL for the caching middleware
         */
        this.initRoutes = () => {
            //#region PID Vehicle Positions
            this.router.get("/", [
                (0, express_validator_1.query)("cisTripNumber").optional().isNumeric().not().isArray(),
                (0, express_validator_1.query)("routeId").optional().not().isArray(),
                (0, express_validator_1.query)("routeShortName").optional().not().isArray(),
                (0, express_validator_1.query)("includeNotTracking").optional().isBoolean().not().isArray(),
                (0, express_validator_1.query)("includeNotPublic").optional().isBoolean().not().isArray(),
                (0, express_validator_1.query)("updatedSince").optional().isISO8601().not().isArray(),
                (0, express_validator_1.query)("preferredTimezone").optional().isIn(constants_1.ValidationArrays.preferredTimezone).not().isArray(),
            ], (0, Validation_1.paginationLimitMiddleware)(this.constructor.name), Validation_1.checkErrors, 
            // max-age 5 seconds, stale-while-revalidate 5 seconds
            this.cacheHeaderMiddleware.getMiddleware(5, 5), this.compressionByDefaultMiddleware.getMiddleware(), this.GetAll);
            this.router.get("/:id", [
                (0, express_validator_1.param)("id").exists(),
                (0, express_validator_1.query)("includeNotTracking").optional().isBoolean().not().isArray(),
                (0, express_validator_1.query)("includePositions").optional().isBoolean().not().isArray(),
                (0, express_validator_1.query)("includeNotPublic").optional().isBoolean().not().isArray(),
                (0, express_validator_1.query)("preferredTimezone").optional().not().isEmpty({ ignore_whitespace: true }),
            ], Validation_1.checkErrors, 
            // max-age 5 seconds, stale-while-revalidate 5 seconds
            this.cacheHeaderMiddleware.getMiddleware(5, 5), this.compressionByDefaultMiddleware.getMiddleware(), this.GetOne);
            //#endregion
            //#region GTFS Realtime
            this.router.get("/gtfsrt/trip_updates.pb", this.cacheHeaderMiddleware.getMiddleware(40, 50), this.GetGtfsRtFeed("trip_updates"));
            this.router.get("/gtfsrt/vehicle_positions.pb", this.cacheHeaderMiddleware.getMiddleware(40, 50), this.GetGtfsRtFeed("vehicle_positions"));
            this.router.get("/gtfsrt/pid_feed.pb", this.cacheHeaderMiddleware.getMiddleware(40, 50), this.GetGtfsRtFeed("pid_feed"));
            this.router.get("/gtfsrt/alerts.pb", this.cacheHeaderMiddleware.getMiddleware(40, 50), this.GetGtfsRtFeed("alerts"));
            //#endregion
        };
        this.router = (0, express_1.Router)();
        this.redisConnector = ioc_1.OutputGatewayContainer.resolve(ioc_1.ContainerToken.RedisConnector);
        this.cacheHeaderMiddleware = ioc_1.OutputGatewayContainer.resolve(ioc_1.ContainerToken.CacheHeaderMiddleware);
        this.compressionByDefaultMiddleware = ioc_1.OutputGatewayContainer.resolve(ioc_1.ContainerToken.CompressionByDefaultMiddleware);
        this.tripWithPositionRepository = data_access_1.repositories.tripWithLastPositionRepository;
        this.initRoutes();
    }
}
exports.V2VehiclePositionsRouter = V2VehiclePositionsRouter;
const v2VehiclepositionsRouter = new V2VehiclePositionsRouter();
exports.v2VehiclepositionsRouter = v2VehiclepositionsRouter;
//# sourceMappingURL=V2VehiclePositionsRouter.js.map