"use strict";
/**
 * `routes` submodule. Defines any routes that need to be exposed and
 * available for other nodes to query.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initRoutes = void 0;
const CycleChain = __importStar(require("../CycleChain"));
const CycleChain_1 = require("../CycleChain");
const Context_1 = require("../Context");
const NodeList = __importStar(require("../NodeList"));
const Archivers = __importStar(require("../Archivers"));
const CycleCreator = __importStar(require("../CycleCreator"));
const JoinV2 = __importStar(require("../Join/v2"));
const ServiceQueue = __importStar(require("../ServiceQueue"));
const profiler_1 = require("../../utils/profiler");
const logger_1 = require("../../logger");
const utils_1 = require("../../utils");
const cycle_monitoring_routes_1 = require("./cycle-monitoring-routes");
/** An endpoint that returns the latest node list hash. */
const validatorListHashRoute = {
    method: 'GET',
    name: 'validator-list-hash',
    handler: (_req, res) => {
        const nextCycleTimestamp = CycleCreator.nextQ1Start;
        res.json({ nodeListHash: NodeList.getNodeListHash(), nextCycleTimestamp });
    },
};
/** An endpoint that returns the latest archiver list hash. */
const archiverListHashRoute = {
    method: 'GET',
    name: 'archiver-list-hash',
    handler: (_req, res) => {
        res.json({ archiverListHash: Archivers.getArchiverListHash() });
    },
};
/** An endpoint that returns the latest standby node list hash. */
const standbyListHashRoute = {
    method: 'GET',
    name: 'standby-list-hash',
    handler: (_req, res) => {
        res.json({ standbyNodeListHash: JoinV2.getStandbyListHash() });
    },
};
/** An endpoint that returns the latest txList hash. */
const txListHashRoute = {
    method: 'GET',
    name: 'tx-list-hash',
    handler: (_req, res) => {
        res.send({ txListHash: ServiceQueue.getTxListHash() });
    },
};
/** An endpoint that returns the last cycle's marker (hash). */
const newestCycleHashRoute = {
    method: 'GET',
    name: 'current-cycle-hash',
    handler: (_req, res) => {
        res.json({ currentCycleHash: CycleChain.getCurrentCycleMarker() });
    },
};
/** An endpoint that returns the last hashed validator list if the expected (requested)
 * hash matches. */
const validatorListRoute = {
    method: 'GET',
    name: 'validator-list',
    handler: (req, res) => {
        let respondSize = 0;
        profiler_1.profilerInstance.scopedProfileSectionStart('validator-list', false);
        try {
            const expectedHash = req.query.hash;
            // return the validator list if the hash from the requester matches
            if (expectedHash && expectedHash === NodeList.getNodeListHash()) {
                //res.json(NodeList.getLastHashedNodeList())
                const getLastHashedNodeList = NodeList.getLastHashedNodeList();
                respondSize = (0, utils_1.jsonHttpResWithSize)(res, getLastHashedNodeList);
            }
            else {
                /* prettier-ignore */ if (logger_1.logFlags.debug)
                    console.error(`rejecting validator list request: expected '${expectedHash}' != '${NodeList.getNodeListHash()}'`);
                res.status(404).json({ error: `validator list with hash '${expectedHash}' not found` });
            }
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('validator-list', respondSize);
        }
    },
};
/** An endpoint that returns the last hashed archiver list if the expected (requested)
 * hash matches. */
const archiverListRoute = {
    method: 'GET',
    name: 'archiver-list',
    handler: (req, res) => {
        profiler_1.profilerInstance.scopedProfileSectionStart('archiver-list', false);
        const expectedHash = req.query.hash;
        // return the archiver list if the hash from the requester matches
        if (expectedHash && expectedHash === Archivers.getArchiverListHash()) {
            res.json(Archivers.getLastHashedArchiverList());
        }
        else {
            /* prettier-ignore */ if (logger_1.logFlags.debug)
                console.error(`rejecting archiver list request: expected '${expectedHash}' != '${Archivers.getArchiverListHash()}'`);
            res.status(404).json({ error: `archiver list with hash '${expectedHash}' not found` });
        }
        profiler_1.profilerInstance.scopedProfileSectionEnd('archiver-list');
    },
};
/** An endpoint that returns the last hashed standby list if the expected (requested)
 * hash matches. */
const standbyListRoute = {
    method: 'GET',
    name: 'standby-list',
    handler: (req, res) => {
        let respondSize = 0;
        profiler_1.profilerInstance.scopedProfileSectionStart('standby-list', false);
        try {
            const expectedHash = req.query.hash;
            // return the standby list if the hash from the requester matches
            if (expectedHash && expectedHash === JoinV2.getStandbyListHash()) {
                const standbyList = JoinV2.getLastHashedStandbyList();
                //todo could make a helper that does response but gets size to
                // const standbyListStr = JSON.stringify(standbyList)
                // respondSize = standbyListStr.length
                // res.write(standbyListStr)
                // res.end()
                respondSize = (0, utils_1.jsonHttpResWithSize)(res, standbyList);
                //res.json(standbyList)
            }
            else {
                /* prettier-ignore */ if (logger_1.logFlags.debug)
                    console.error(`rejecting standby list request: expected '${expectedHash}' != '${JoinV2.getStandbyListHash()}'`);
                res.status(404).json({ error: `standby list with hash '${expectedHash}' not found` });
            }
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('standby-list', respondSize);
        }
    },
};
const txListRoute = {
    method: 'GET',
    name: 'tx-list',
    handler: (req, res) => {
        profiler_1.profilerInstance.scopedProfileSectionStart('tx-list', false);
        try {
            const expectedHash = req.query.hash;
            if (expectedHash && expectedHash === ServiceQueue.getTxListHash()) {
                const txList = ServiceQueue.getTxList();
                res.json(txList);
            }
            else {
                /* prettier-ignore */ if (logger_1.logFlags.debug)
                    console.error(`rejecting tx list request: expected '${expectedHash}' != '${ServiceQueue.getTxListHash()}'`);
                res.status(404).send(`tx list with hash '${expectedHash}' not found`);
            }
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('tx-list');
        }
    },
};
/** An endpoint that returns the cycle corresponding to the requested marker. */
const cycleByMarkerRoute = {
    method: 'GET',
    name: 'cycle-by-marker',
    handler: (req, res) => {
        profiler_1.profilerInstance.scopedProfileSectionStart('cycle-by-marker', false);
        // get the cycle corresponding to the marker. return it if it exists, or
        // otherwise return an error.
        const cycle = CycleChain.cyclesByMarker[req.query.marker];
        if (cycle) {
            res.json(cycle);
        }
        else {
            res.status(404).json({ error: `cycle with marker '${req.query.marker}' not found` });
        }
        profiler_1.profilerInstance.scopedProfileSectionEnd('cycle-by-marker');
    },
};
const newestCycleRecordRoute = {
    method: 'GET',
    name: 'newest-cycle-record',
    handler: (_req, res) => {
        profiler_1.profilerInstance.scopedProfileSectionStart('newest-cycle-record', false);
        res.json(CycleChain.newest);
        profiler_1.profilerInstance.scopedProfileSectionEnd('newest-cycle-record');
    },
};
/** An endpoint that returns recent cycle markers for historical sync */
const recentCycleMarkersRoute = {
    method: 'GET',
    name: 'recent-cycle-markers',
    handler: (_req, res) => {
        profiler_1.profilerInstance.scopedProfileSectionStart('recent-cycle-markers', false);
        try {
            const cycleCount = Math.min(CycleChain_1.cycles.length, CycleCreator.MAX_CYCLES_TO_KEEP); // Limit to MAX_CYCLES_TO_KEEP
            const recentMarkers = [];
            // Get most recent cycle markers
            for (let i = CycleChain_1.cycles.length - cycleCount; i < CycleChain_1.cycles.length; i++) {
                if (CycleChain_1.cycles[i]) {
                    const marker = CycleCreator.makeCycleMarker(CycleChain_1.cycles[i]);
                    recentMarkers.push(marker);
                }
            }
            // Find the oldest defined cycle in the range
            let oldestCounter = 0;
            for (let i = CycleChain_1.cycles.length - cycleCount; i < CycleChain_1.cycles.length; i++) {
                if (CycleChain_1.cycles[i]) {
                    oldestCounter = CycleChain_1.cycles[i].counter;
                    break;
                }
            }
            res.json({ cycleMarkers: recentMarkers, oldestCounter });
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('recent-cycle-markers');
        }
    },
};
/** An endpoint that returns multiple cycles in batch */
const cyclesBatchRoute = {
    method: 'GET',
    name: 'cycles-batch',
    handler: (req, res) => {
        let respondSize = 0;
        profiler_1.profilerInstance.scopedProfileSectionStart('cycles-batch', false);
        try {
            const markersParam = req.query.markers;
            if (!markersParam) {
                res.status(400).json({ error: 'markers parameter is required' });
                return;
            }
            const markers = markersParam.split(',');
            const maxBatchSize = 50;
            if (markers.length > maxBatchSize) {
                res.status(400).json({ error: `batch size exceeds limit of ${maxBatchSize}` });
                return;
            }
            const cyclesResult = [];
            for (const marker of markers) {
                const cycle = CycleChain.cyclesByMarker[marker];
                if (cycle) {
                    cyclesResult.push(cycle);
                }
            }
            respondSize = (0, utils_1.jsonHttpResWithSize)(res, { cycles: cyclesResult });
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('cycles-batch', respondSize);
        }
    },
};
/** Registers all routes as external routes. */
function initRoutes() {
    const routes = [
        validatorListHashRoute,
        archiverListHashRoute,
        standbyListHashRoute,
        txListHashRoute,
        newestCycleHashRoute,
        validatorListRoute,
        archiverListRoute,
        standbyListRoute,
        txListRoute,
        cycleByMarkerRoute,
        newestCycleRecordRoute,
        recentCycleMarkersRoute,
        cyclesBatchRoute,
    ];
    for (const route of routes) {
        Context_1.network._registerExternal(route.method, route.name, route.handler);
    }
    // Register cycle monitoring routes with debug middleware
    (0, cycle_monitoring_routes_1.registerCycleMonitoringRoutes)(Context_1.network);
}
exports.initRoutes = initRoutes;
//# sourceMappingURL=routes.js.map