"use strict";
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.rollback = exports.removeWithReceipt = exports.deploy = void 0;
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const airnode_node_1 = require("@api3/airnode-node");
const promise_utils_1 = require("@api3/promise-utils");
const infrastructure_1 = require("../infrastructure");
const utils_1 = require("../utils");
const logger = __importStar(require("../utils/logger"));
const infrastructure_2 = require("../utils/infrastructure");
async function deploy(configPath, secretsPath, receiptFile, autoRemove) {
    const secrets = (0, utils_1.parseSecretsFile)(secretsPath);
    const config = (0, airnode_node_1.loadConfig)(configPath, secrets);
    if (config.nodeSettings.cloudProvider.type === 'local') {
        throw (0, infrastructure_2.logAndReturnError)(`Deployer can't deploy to "local" cloud provider`);
    }
    // Deployment is not an atomic operation. It is possible that some resources are deployed even when there is a
    // deployment error. We want to write a receipt file, because the user might use the receipt to remove the deployed
    // resources from the failed deployment. (The removal is not guaranteed, but it's better compared to asking user to
    // remove the resources manually in the cloud provider dashboard).
    const time = new Date();
    const goDeployAirnode = await (0, promise_utils_1.go)(() => (0, infrastructure_1.deployAirnode)(config, configPath, secretsPath, time.getTime()));
    (0, utils_1.writeReceiptFile)(receiptFile, config, time.toISOString(), goDeployAirnode.success);
    if (!goDeployAirnode.success && !autoRemove) {
        logger.fail(`Airnode deployment failed due to unexpected errors.\n` +
            `  It is possible that some resources have been deployed on cloud provider.\n` +
            `  Please use the "remove" command from the deployer CLI to ensure all cloud resources are removed.`, { bold: true });
        throw goDeployAirnode.error;
    }
    if (!goDeployAirnode.success) {
        logger.fail(`Airnode deployment failed due to unexpected errors.\n` +
            `  It is possible that some resources have been deployed on cloud provider.\n` +
            `  Attempting to remove them...\n`, { bold: true });
        // Try to remove deployed resources
        const goRemoveAirnode = await (0, promise_utils_1.go)(() => removeWithReceipt(receiptFile));
        if (!goRemoveAirnode.success) {
            logger.fail(`Airnode removal failed due to unexpected errors.\n` +
                `  It is possible that some resources have been deployed on cloud provider.\n` +
                `  Please check the resources on the cloud provider dashboard and\n` +
                `  use the "remove" command from the deployer CLI to remove them.\n` +
                `  If the automatic removal via CLI fails, remove the resources manually.`, { bold: true });
            throw new infrastructure_2.MultiMessageError([
                'Deployment error:\n' + goDeployAirnode.error.message,
                'Removal error:\n' + goRemoveAirnode.error.message,
            ]);
        }
        logger.succeed('Successfully removed the Airnode deployment');
        throw new Error('Deployment error:\n' + goDeployAirnode.error.message);
    }
    const output = goDeployAirnode.data;
    if (output.httpGatewayUrl) {
        logger.setSecret(output.httpGatewayUrl);
        logger.info(`HTTP gateway URL: ${output.httpGatewayUrl}`, { secrets: true });
    }
    if (output.httpSignedDataGatewayUrl) {
        logger.setSecret(output.httpSignedDataGatewayUrl);
        logger.info(`HTTP signed data gateway URL: ${output.httpSignedDataGatewayUrl}`, { secrets: true });
    }
    if (output.oevGatewayUrl) {
        logger.setSecret(output.oevGatewayUrl);
        logger.info(`OEV gateway URL: ${output.oevGatewayUrl}`, { secrets: true });
    }
    return { creationTime: time };
}
exports.deploy = deploy;
async function removeWithReceipt(receiptFilename) {
    const receipt = (0, utils_1.parseReceiptFile)(receiptFilename);
    const { deploymentId } = receipt.deployment;
    // If the function throws, the CLI will fail with a non zero status code
    await (0, infrastructure_1.removeAirnode)(deploymentId);
}
exports.removeWithReceipt = removeWithReceipt;
async function rollback(deploymentId, versionId, receiptFile, autoRemove) {
    const spinner = logger.getSpinner();
    spinner.start(`Rollback of deployment '${deploymentId}' to version '${versionId}'`);
    if (logger.inDebugMode()) {
        spinner.info();
    }
    const configDirTmp = fs.mkdtempSync(path.join(os.tmpdir(), 'airnode'));
    const configPathTmp = path.join(configDirTmp, 'config.json');
    const secretsPathTmp = path.join(configDirTmp, 'secrets.env');
    try {
        await (0, infrastructure_1.saveDeploymentFiles)(deploymentId, versionId, configPathTmp, secretsPathTmp);
        const { creationTime } = await deploy(configPathTmp, secretsPathTmp, receiptFile, autoRemove);
        const secrets = (0, utils_1.parseSecretsFile)(secretsPathTmp);
        const config = (0, airnode_node_1.loadConfig)(configPathTmp, secrets);
        const { airnodeWalletMnemonic, cloudProvider, stage, nodeVersion } = config.nodeSettings;
        const airnodeAddress = (0, utils_1.deriveAirnodeAddress)(airnodeWalletMnemonic);
        const newVersionId = (0, airnode_node_1.deriveDeploymentVersionId)(cloudProvider, airnodeAddress, stage, nodeVersion, `${creationTime.getTime()}`);
        spinner.succeed(`Rollback of deployment '${deploymentId}' successful, new version '${newVersionId}' with configuration from version '${versionId}' created`);
    }
    finally {
        fs.rmSync(configDirTmp, { recursive: true });
    }
}
exports.rollback = rollback;
//# sourceMappingURL=commands.js.map