"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const identity_1 = tslib_1.__importDefault(require("lodash/identity"));
const listr_1 = tslib_1.__importDefault(require("listr"));
const yn_1 = tslib_1.__importDefault(require("yn"));
const utils = tslib_1.__importStar(require("./utils"));
const errors_1 = require("./errors");
const logger_1 = require("./logger");
const prompts_1 = require("./prompts");
const constants_1 = require("./constants");
const AZS_COUNT = 3;
const EIP_LIMIT = 5;
exports.getStackName = utils.getServicesStackName;
exports.getServicesStackId = (cloudformation, mycloudStackName) => tslib_1.__awaiter(this, void 0, void 0, function* () {
    const servicesStackName = utils.getServicesStackName(mycloudStackName);
    return utils.getStackId(cloudformation, servicesStackName);
});
exports.configureKYCServicesStack = (conf, { truefaceSpoof, rankOne, client, accountId, mycloudStackName, mycloudRegion, stackParameters = {}, }) => tslib_1.__awaiter(this, void 0, void 0, function* () {
    const servicesStackName = exports.getStackName(mycloudStackName);
    const servicesStackId = yield exports.getServicesStackId(client.cloudformation, mycloudStackName);
    const exists = !!servicesStackId;
    const bucket = yield conf.getPrivateConfBucket();
    const bucketEncryptionKey = yield utils.getBucketEncryptionKey({ s3: client.s3, kms: client.kms, bucket });
    const discoveryObjPath = `${bucket}/discovery/ecs-services.json`;
    if (typeof truefaceSpoof === 'boolean' && typeof rankOne === 'boolean') {
    }
    else {
        const tfVerb = truefaceSpoof ? 'enable' : 'disable';
        const roVerb = rankOne ? 'enable' : 'disable';
        yield prompts_1.confirmOrAbort(`${tfVerb} TrueFace Spoof, ${roVerb} RankOne?`);
    }
    const repoNames = [
        constants_1.REPO_NAMES.nginx,
        truefaceSpoof && constants_1.REPO_NAMES.truefaceSpoof,
        rankOne && constants_1.REPO_NAMES.rankOne,
    ].filter(identity_1.default).join(', ');
    yield prompts_1.confirmOrAbort(`has Tradle given you access to the following ECR repositories? ${repoNames}`);
    const enabledServices = Object.keys(constants_1.REPO_NAMES).filter(service => service in constants_1.LICENSE_PATHS);
    if (enabledServices.length) {
        yield checkLicenses({
            s3: client.s3,
            licenses: enabledServices,
            bucket,
        });
    }
    const region = mycloudRegion;
    const azsCount = AZS_COUNT;
    const availabilityZones = exists
        ? (yield getServicesStackInfo(client, { stackId: servicesStackId })).availabilityZones
        : yield prompts_1.chooseAZs(client, { region, count: azsCount });
    const usedEIPCount = yield utils.getUsedEIPCount(client.ec2);
    if (!exists && EIP_LIMIT - usedEIPCount < azsCount) {
        yield prompts_1.confirmOrAbort(`WARNING: your account has ${usedEIPCount} Elastic IPs in use in region ${region}.
This stack will create ${azsCount} more. AWS's base limit is 5 per region, so this stack may fail.
You can request a limit increase from AWS here: https://console.aws.amazon.com/support/v1#/case/create?issueType=service-limit-increase&limitType=service-code-vpc
Continue?`);
    }
    const willDeleteStack = !(truefaceSpoof || rankOne);
    if (willDeleteStack) {
        yield prompts_1.confirmOrAbort(`you've disabled all the services disabled, can I delete the KYC services stack?`);
        logger_1.logger.info('deleting KYC services stack: ${servicesStackId}, ETA: 5-10 minutes');
        yield utils.deleteStackAndWait({
            cloudformation: client.cloudformation,
            params: {
                StackName: servicesStackId
            },
        });
        return;
    }
    const enableSSH = yn_1.default(yield prompts_1.confirm('enable SSH into the instances?', false));
    const parameters = availabilityZones.map((az, i) => ({
        ParameterKey: `AZ${(i + 1)}`,
        ParameterValue: az
    }));
    parameters.push({
        ParameterKey: 'S3PathToWriteDiscovery',
        ParameterValue: discoveryObjPath
    });
    if (truefaceSpoof) {
        parameters.push({
            ParameterKey: 'EnableTruefaceSpoof',
            ParameterValue: 'true'
        });
        parameters.push({
            ParameterKey: 'S3PathToTrueFaceLicense',
            ParameterValue: `${bucket}/${constants_1.LICENSE_PATHS.truefaceSpoof}`,
        });
    }
    if (rankOne) {
        parameters.push({
            ParameterKey: 'EnableRankOne',
            ParameterValue: 'true',
        });
        parameters.push({
            ParameterKey: 'S3PathToRankOneLicense',
            ParameterValue: `${bucket}/${constants_1.LICENSE_PATHS.rankOne}`,
        });
    }
    if (enableSSH) {
        const key = yield prompts_1.chooseEC2KeyPair(client.ec2);
        parameters.push({
            ParameterKey: 'KeyName',
            ParameterValue: key
        });
    }
    if (bucketEncryptionKey) {
        parameters.push({
            ParameterKey: 'S3KMSKey',
            ParameterValue: `arn:aws:kms:${mycloudRegion}:${accountId}:${bucketEncryptionKey}`
        });
    }
    for (let ParameterKey in stackParameters) {
        let ParameterValue = String(stackParameters[ParameterKey]);
        parameters.push({ ParameterKey, ParameterValue });
    }
    yield prompts_1.confirmOrAbort(`are you freaking ready?`);
    const tasks = [
        {
            title: 'validate template',
            task: (ctx) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                const params = {
                    StackName: servicesStackId || servicesStackName,
                    Parameters: parameters,
                    TemplateURL: constants_1.SERVICES_STACK_TEMPLATE_URL,
                    Capabilities: ['CAPABILITY_NAMED_IAM']
                };
                let method;
                let waitMethod;
                if (exists) {
                    method = 'updateStackInRegion';
                    waitMethod = 'awaitStackUpdate';
                }
                else {
                    method = 'createStackInRegion';
                    waitMethod = 'awaitStackCreate';
                    params.DisableRollback = true;
                }
                ctx.wait = yield utils[method]({ params, region });
            }),
        },
        {
            title: exists
                ? `update KYC services stack`
                : `create KYC services stack (this will take ~20 minutes)`,
            task: ctx => ctx.wait(),
        },
        {
            title: 'poke MyCloud to pick up update',
            task: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
                yield conf.reboot();
            })
        },
    ];
    yield new listr_1.default(tasks).run();
});
const checkLicenses = ({ s3, bucket, licenses }) => tslib_1.__awaiter(this, void 0, void 0, function* () {
    if (!licenses.length)
        return;
    const licenseToDest = licenses.map(license => {
        return `${license}:

  bucket: ${bucket}
  key: ${constants_1.LICENSE_PATHS[license]}`;
    });
    yield prompts_1.confirmOrAbort(`have you uploaded the following licenses?

${licenseToDest.join('\n\n')}
`);
    const opts = { s3, bucket };
    try {
        yield Promise.all(licenses.map(service => utils.assertS3ObjectExists(Object.assign({}, opts, { key: constants_1.LICENSE_PATHS[service] }))));
    }
    catch (err) {
        throw new errors_1.Errors.NotFound(`Missing license file(s): ${err.message}`);
    }
});
const getServicesStackInfo = (client, { stackId }) => tslib_1.__awaiter(this, void 0, void 0, function* () {
    const { Stacks } = yield client.cloudformation.describeStacks({
        StackName: stackId,
    }).promise();
    const { Outputs } = Stacks[0];
    const availabilityZones = getOutput(Outputs, 'AvailabilityZones').split(',');
    const region = getOutput(Outputs, 'Region');
    return {
        region,
        availabilityZones,
    };
});
const getOutput = (Outputs, key) => Outputs.find(o => o.OutputKey === key).OutputValue;
exports.deleteCorrespondingServicesStack = ({ cloudformation, stackId }) => tslib_1.__awaiter(this, void 0, void 0, function* () {
    const { stackName } = utils.parseStackArn(stackId);
    const servicesStackId = yield exports.getServicesStackId(cloudformation, stackName);
    if (!servicesStackId) {
        throw new errors_1.Errors.NotFound(`services stack for mycloud stack: ${stackId}`);
    }
    logger_1.logger.info(`KYC services stack: deleting ${servicesStackId}, ETA: 5-10 minutes`);
    yield utils.deleteStackAndWait({
        cloudformation,
        params: {
            StackName: servicesStackId
        },
    });
    logger_1.logger.info(`KYC services stack: deleted ${servicesStackId}`);
});
//# sourceMappingURL=kyc-services.js.map