"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IdentityHandlerRegistry = exports.IdentityAggregator = void 0;
const tslib_1 = require("tslib");
const path = require("path");
const _ = require("lodash");
const codiac_relay_contracts_1 = require("@codiac.io/codiac-relay-contracts");
const npmjs_identity_adapter_1 = require("./extensions/npmjs-identity-adapter");
const azart_identity_adapter_1 = require("./extensions/azart-identity-adapter");
const npm_config_repo_1 = require("./data/npm-config-repo");
const dx_constants_1 = require("./dx-constants");
const ops_constants_1 = require("./ops-constants");
/** Oversees the work required for all identity types,
 *  and ensures that identities are managed by the proper IIdentityHandler.
 *  Use this class to perform work on identities.
 */
class IdentityAggregator {
    constructor(_projectRoot, logger) {
        this._projectRoot = _projectRoot;
        this.logger = logger;
    }
    createIdentity(provider, token, input) {
        let adapter = IdentityHandlerRegistry.getAdapterFor(provider, this._projectRoot, this.logger);
        if (!adapter) {
            throw new Error(`Cannot continue: No default identity handler has been registered to support the given identity.`);
        }
        let identity = adapter.createIdentity(token, input);
        return identity;
    }
    syncIdentities(identitySet) {
        return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                // Transpose the identitySet to key by provider
                let allocated = {};
                for (let tokenName in identitySet) {
                    let identity = identitySet[tokenName];
                    if (!allocated[identity.provider])
                        allocated[identity.provider] = [];
                    allocated[identity.provider].push(identity);
                }
                // Assemble all the npmrc entries 
                let npmrcMods = [];
                for (let provider in allocated) {
                    // This is a safe cast bc we just downcasted it above this in this method.
                    let adapter = IdentityHandlerRegistry.getAdapterFor(provider, this._projectRoot, this.logger);
                    if (!adapter) {
                        throw new Error(`Cannot continue: No default identity handler has been registered to support the given identity.`);
                    }
                    let providerMods = yield adapter.syncIdentities(allocated[provider]);
                    npmrcMods.push(...providerMods);
                }
                // Write the npmrc docs
                yield this.syncIdentitiesWithNpmrc(npmrcMods);
                // if (overridingDefaultRegistry) {
                //   this.logger.warn(`NOTE: your ${this.provider} identities are setting the default registry for npm to [${lastDefaultReg}].`);
                // }
                resolve();
            }
            catch (err) {
                reject(err);
            }
        }));
    }
    syncIdentitiesWithNpmrc(npmrcIdentities) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    let npmRepo = new npm_config_repo_1.NpmConfigRepo(this._projectRoot);
                    // ------------------------------------------------------------------------------
                    // 1) Write the identities to the user npmrc file as before
                    // Gather up what was in the existing user config
                    // stripped of any auth tokens or scope variables
                    let userNpmrcRelPath = path.join(ops_constants_1.OpsConstants.PROJECT_USER_CONFIG_FOLDER_NAME, dx_constants_1.DxConstants.NPM_PROJECT_USER_CONFIG_FILENAME);
                    let userNpmrcAbsPath = path.join(this._projectRoot, userNpmrcRelPath);
                    let existingTokenSettings = yield npmRepo.loadNpmrc(userNpmrcAbsPath);
                    let userNpmrc = npmRepo.scrubRegistriesFrom(existingTokenSettings);
                    let userIsDirty = false;
                    // ------------------------------------------------------------------------------
                    // 2) Ensure that the project npmrc redirects the user config to our project user folder
                    //    If the proj npmrc isnt redirecting the user level npmrc to live in our project-user folder, 
                    //    then put it there and reconfigure for it.  Involves:  "./.npmrc", "$HOME/.npmrc", "./.codiac-user/.npmrc-user"
                    //    via `npm config get userconfig`
                    let projectNpmrcFullPathName = path.join(this._projectRoot, ".npmrc");
                    let existingProjNpmrc = yield npmRepo.loadNpmrc(projectNpmrcFullPathName);
                    let projNpmrc = npmRepo.scrubRegistriesFrom(existingProjNpmrc);
                    let projIsDirty = false;
                    if (projNpmrc.userconfig != userNpmrcRelPath) {
                        // TODO:  Ensure that .gitignore is preventing the .codiac-user folder from being committed.
                        projNpmrc.userconfig = userNpmrcRelPath;
                        // projNpmrc = npmRepo.scrubRegistriesFrom(projNpmrc)
                        projIsDirty = true;
                    }
                    for (let index in npmrcIdentities) {
                        let npmrcMod = npmrcIdentities[index];
                        let exists = (existingTokenSettings[npmrcMod.tokenSetting]) ? true : false;
                        // Modify proj user npmrc (sensitive contents)
                        if (!_.isEmpty(npmrcMod.projUserEntries)) {
                            userNpmrc = _.assign(userNpmrc, npmrcMod.projUserEntries);
                            userIsDirty = true;
                            this.logger.detail(`${(exists) ? "Overwrote" : "Added"} ${npmrcMod.identity.provider} token reference [${npmrcMod.identity.tokenName}] to the .npmrc file for use during the image build.`);
                        }
                        // Modify the proj npmrc (not sensitive and checked into scc)
                        if (!_.isEmpty(npmrcMod.projEntries)) {
                            projNpmrc = _.assign(projNpmrc, npmrcMod.projEntries);
                            projIsDirty = true;
                        }
                    }
                    // This can result in confusion if the registry they're pointing to 
                    // doesnt relay package requests to npmjs. 
                    let defaultRegistryOverride = userNpmrc["registry"];
                    if (defaultRegistryOverride) {
                        this.logger.warn(`Pointed default npm registry to [${defaultRegistryOverride}].`);
                    }
                    if (userIsDirty) {
                        npmRepo.saveNpmrc(userNpmrc, userNpmrcAbsPath);
                    }
                    if (projIsDirty) {
                        npmRepo.saveNpmrc(projNpmrc, projectNpmrcFullPathName);
                    }
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
}
exports.IdentityAggregator = IdentityAggregator;
/** IOC for all supported Identity provider adpaters */
class IdentityHandlerRegistry {
    static getAll() {
        let all = [];
        for (let pvd in codiac_relay_contracts_1.IdentityProvider) {
            all.push(pvd);
        }
        return all;
    }
    static getAdapterFor(provider, projectRoot, logger) {
        // When this gets to be more than just a few, move them out of the switch and into a registry.
        switch (provider) {
            case codiac_relay_contracts_1.IdentityProvider.npm:
                return new npmjs_identity_adapter_1.npmjsIdentityAdapter(projectRoot, logger);
                // let platform = new NpmPlatform(this.logger);
                // platform.addRegistryAdapter(npmjsRegistryAdapter, "npmjs");
                // platform.addRegistryAdapter(azartRegistryAdapter, "azart");
                // return platform;
                break;
            case codiac_relay_contracts_1.IdentityProvider.azart:
                return new azart_identity_adapter_1.azartIdentityAdapter(projectRoot, logger);
            // case IdentityProvider.docker:
            //   let platform = new DockerPlatform(this.logger);
            //   platform.addRegistryAdapter(dockerHubAdapter, "dockerhub");
            //   platform.addRegistryAdapter(acrAdapter, "acr");  // Azure container registry
            //   return platform;
            //   break;
            case codiac_relay_contracts_1.IdentityProvider.other:
                // Are we going to use a generic platform object?
                break;
        }
    }
}
exports.IdentityHandlerRegistry = IdentityHandlerRegistry;
IdentityHandlerRegistry.supportedProviders = IdentityHandlerRegistry.getAll();
//# sourceMappingURL=i-identity-handler.js.map