"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckSavedRowsAndReplaceTablesTask = void 0;
const DataCacheManager_1 = require("../../../helpers/DataCacheManager");
const SourceTableSuffixEnum_1 = require("../../../helpers/SourceTableSuffixEnum");
const Di_1 = require("../../../ioc/Di");
const RopidGtfsContainerToken_1 = require("../../../ioc/RopidGtfsContainerToken");
const constants_1 = require("../../../../vehicle-positions/workers/vehicle-positions/constants");
const CoreToken_1 = require("@golemio/core/dist/helpers/ioc/CoreToken");
const integration_engine_1 = require("@golemio/core/dist/integration-engine");
const workers_1 = require("@golemio/core/dist/integration-engine/workers");
const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors");
const DownloadDataInputSchema_1 = require("./schema/DownloadDataInputSchema");
class CheckSavedRowsAndReplaceTablesTask extends workers_1.AbstractTask {
    constructor(queuePrefix) {
        super(queuePrefix);
        this.queueName = "checkSavedRowsAndReplaceTables";
        this.queueTtl = 23 * 60 * 60 * 1000; // 23 hours
        this.schema = DownloadDataInputSchema_1.DatasetsInputSchema;
        this.logger = Di_1.RopidGtfsContainer.resolve(CoreToken_1.CoreToken.Logger);
        this.config = Di_1.RopidGtfsContainer.resolve(CoreToken_1.CoreToken.SimpleConfig);
        this.metadataRepository = Di_1.RopidGtfsContainer.resolve(RopidGtfsContainerToken_1.RopidGtfsContainerToken.RopidGtfsMetadataRepository);
        this.dataCacheManager = DataCacheManager_1.DataCacheManager.getInstance();
        this.precomputeTablesFacade = Di_1.RopidGtfsContainer.resolve(RopidGtfsContainerToken_1.RopidGtfsContainerToken.PrecomputedTablesFacade);
        this.ropidGtfsRepository = Di_1.RopidGtfsContainer.resolve(RopidGtfsContainerToken_1.RopidGtfsContainerToken.RopidGtfsRepository);
        this.ropidGtfsFacade = Di_1.RopidGtfsContainer.resolve(RopidGtfsContainerToken_1.RopidGtfsContainerToken.RopidGtfsFacade);
    }
    async execute(data) {
        const { notDeployed, datasetDeployInfo } = await this.getDatasetsToDeploy(data);
        if (data.datasets.length !== notDeployed.length) {
            const names = notDeployed.map((el) => el.dataset);
            this.logger.error(`Error while synchronized download of datasets: [${names}] of [${data.datasets}] deployed already`);
        }
        if (!notDeployed.length) {
            this.logger.debug(`Datasets status: already deployed`);
            return;
        }
        const notDeployedVersions = notDeployed.map((el) => ({ dataset: el.dataset, version: el.lastModified.version }));
        const allSaved = await this.metadataRepository.checkAllTablesHasSavedState(notDeployedVersions);
        try {
            await this.checkSavedRows(allSaved, datasetDeployInfo);
            await this.precomputeTablesFacade.createAndPopulatePrecomputedTmpTables(SourceTableSuffixEnum_1.SourceTableSuffixEnum.Tmp);
            await this.ropidGtfsFacade.replaceTables(notDeployedVersions);
            await this.dataCacheManager.cleanCache();
            await this.ropidGtfsRepository.cleanTmpAndOldTables();
            const rabbitExchangeName = this.config.getValue("env.RABBIT_EXCHANGE_NAME");
            await Promise.all([
                // send message to VP worker to refresh GTFS trip data (see task description for more info)
                integration_engine_1.QueueManager.sendMessageToExchange(`${rabbitExchangeName}.${constants_1.WORKER_NAME.toLowerCase()}`, "refreshGTFSTripData", {}),
                // send message to GTFS timetable worker to refresh public GTFS departure cache
                //   so that the new data is available in the public (Lítačka) API
                integration_engine_1.QueueManager.sendMessageToExchange(this.queuePrefix, "refreshPublicGtfsDepartureCache", {}),
                integration_engine_1.QueueManager.sendMessageToExchange(this.queuePrefix, "refreshGtfsStopsCache", {}),
            ]);
        }
        catch (err) {
            await this.retryOrThrow(notDeployedVersions, data, err);
        }
    }
    async retryOrThrow(notDeployedVersions, data, err) {
        // log failed saving process
        await Promise.all(notDeployedVersions.map(async (el) => {
            await this.metadataRepository.rollbackFailedSaving(el.dataset, el.version);
        }));
        // check number of tries
        const retries = await Promise.all(notDeployedVersions.map(async (el) => {
            return await this.metadataRepository.getNumberOfDownloadRetries(el.dataset, el.version);
        }));
        await this.ropidGtfsRepository.cleanTmpAndOldTables();
        if (Math.max(...retries) <= 5) {
            // send new downloadFiles, log it and finish
            integration_engine_1.QueueManager.sendMessageToExchange(this.queuePrefix, "downloadDatasets", data);
            integration_engine_1.IntegrationErrorHandler.handle(new golemio_errors_1.GeneralError(`Error while checking RopidGTFS saved rows. Attempt number ${Math.min(...retries)} was resent.`, this.constructor.name, err));
        }
        else {
            // at least refresh precomputed tables and finish with error
            integration_engine_1.QueueManager.sendMessageToExchange(this.queuePrefix, "refreshPrecomputedTables", {});
            throw new golemio_errors_1.GeneralError("Error while checking RopidGTFS saved rows.", this.constructor.name, err);
        }
    }
    async checkSavedRows(allSaved, datasetDeployInfo) {
        if (!allSaved) {
            throw new golemio_errors_1.GeneralError("Some GTFS datasets did not properly save", this.constructor.name);
        }
        await Promise.all(datasetDeployInfo.map(async (el) => {
            await this.ropidGtfsFacade.checkSavedTmpTables(el.dataset, el.lastModified.version);
        }));
    }
    async getDatasetsToDeploy(data) {
        const datasetDeployInfo = await Promise.all(data.datasets.map(async (dataset) => {
            const lastModified = await this.metadataRepository.getLastModified(dataset);
            const isDeployed = await this.metadataRepository.checkIfNewVersionIsAlreadyDeployed(dataset, lastModified.version);
            return { dataset, lastModified, isDeployed };
        }));
        this.logger.debug(`Datasets status: ${JSON.stringify(datasetDeployInfo)}`);
        const notDeployed = datasetDeployInfo.filter((info) => !info.isDeployed);
        return { notDeployed, datasetDeployInfo };
    }
}
exports.CheckSavedRowsAndReplaceTablesTask = CheckSavedRowsAndReplaceTablesTask;
//# sourceMappingURL=CheckSavedRowsAndReplaceTablesTask.js.map