"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectContextRepo = exports.CliGlobalConfigRepo = exports.JsonFileRepoFor = void 0;
const tslib_1 = require("tslib");
const path = require("path");
const fs = require("fs");
const Case = require("case");
const inversify_1 = require("inversify");
const utilities_1 = require("@codiac.io/codiac-common/utilities");
const codiac_relay_contracts_1 = require("@codiac.io/codiac-relay-contracts");
const codiac_ops_common_1 = require("@codiac.io/codiac-ops-common");
const entities_1 = require("../entities");
const cli_path_walker_1 = require("../cli-path-walker");
const ops_constants_1 = require("../ops-constants");
const dx_constants_1 = require("../dx-constants");
/** Performs cruds on an entity stored on the local hard drive as single json file.
 */
let JsonFileRepoFor = class JsonFileRepoFor {
    constructor(settings) {
        this.settings = settings;
    }
};
JsonFileRepoFor = tslib_1.__decorate([
    (0, inversify_1.injectable)(),
    tslib_1.__param(0, (0, inversify_1.unmanaged)()),
    tslib_1.__metadata("design:paramtypes", [Object])
], JsonFileRepoFor);
exports.JsonFileRepoFor = JsonFileRepoFor;
let CliGlobalConfigRepo = class CliGlobalConfigRepo extends JsonFileRepoFor {
    constructor(cliEnviro) {
        super({ parentFolder: cliEnviro.cliConfigDir, fileName: entities_1.CliConfig.FILENAME });
        this.entityTypeName = (0, utilities_1.typeNameOf)(entities_1.CliConfig);
    }
    // tryCreate(entity: T, options?: IRepoOptions): Promise<contracts.SingleResult<T>>;
    /** Returns an empty config object when undefined.
     * TODO: Consider changing signature to also return undefined.
     */
    read() {
        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 pathName = path.join(this.settings.parentFolder, this.settings.fileName);
                    let config = codiac_ops_common_1.JsonUtils.deserializeJsonFile(pathName);
                    if (!config)
                        config = new entities_1.CliConfig();
                    resolve(config);
                }
                catch (err) {
                    reject(new Error(`Error reading ${this.entityTypeName}: ${err.message || err.stderr || ""}.\n${err}`));
                }
            }));
        });
    }
    // tryUpdate(entity: T, options?: IRepoOptions): Promise<contracts.SingleResult<T>>;
    upsert(entity) {
        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 pathName = path.join(this.settings.parentFolder, this.settings.fileName);
                    codiac_ops_common_1.JsonUtils.serializeJsonFile(entity, pathName);
                    resolve(entity);
                }
                catch (err) {
                    reject(new Error(`Error writing ${this.entityTypeName}: ${err.message || err.stderr || ""}.\n${err}`));
                }
            }));
        });
    }
    // tryUpdatePartial(entity: Partial<T>, options?: IRepoOptions): Promise<contracts.SingleResult<Partial<T>>>;
    // tryPatch(operations: contracts.PatchSpecForOne<T>, options?: IRepoOptions): Promise<contracts.SingleResult<T>>;
    // tryDelete(idSpec: contracts.IdSpec, options?: IRepoOptions): Promise<contracts.SingleResult<T>>;
    /** Deserializes the global Codiac CLI configuration file.
   * @deprecated Use cliGlobalConfigRepo.read() instead.
  */
    read_sync() {
        // cli.log(`Reading cli config from: ${path.join(this.cliConfigDir, CliConfig.FILENAME)}`);
        // let config = JsonUtils.deserializeJsonFile<CliConfig>(path.join(this.cliEnviro.cliConfigDir, CliConfig.FILENAME));
        let config = codiac_ops_common_1.JsonUtils.deserializeJsonFile(path.join(this.settings.parentFolder, this.settings.fileName));
        // TODO: trim off any properties that dont exist on the CliConfig prototype.
        return config;
    }
    /** Serializes the global Codiac CLI configuration object.
     *
     * @deprecated Use cliGlobalConfigRepo.upsert() instead.
    */
    write_sync(config) {
        // JsonUtils.serializeJsonFile(config, path.join(this.cliEnviro.cliConfigDir, CliConfig.FILENAME));
        codiac_ops_common_1.JsonUtils.serializeJsonFile(config, path.join(this.settings.parentFolder, this.settings.fileName));
    }
};
CliGlobalConfigRepo = tslib_1.__decorate([
    (0, inversify_1.injectable)(),
    tslib_1.__param(0, (0, inversify_1.inject)(entities_1.CliEnviro)),
    tslib_1.__metadata("design:paramtypes", [entities_1.CliEnviro])
], CliGlobalConfigRepo);
exports.CliGlobalConfigRepo = CliGlobalConfigRepo;
// /** TODO: Move this to codiac-cli-common
//  * Legacy methods extracted from ProjectContextRepo (formerly CliContextRepo)
//  *
//  */
// @injectable()
// export class CliGlobalConfigRepo_sync {
//   constructor(@inject(CliEnviro) private cliEnviro: CliEnviro) {
//   }
//   // =========================================================================================== //
//   //                                                                                             //
//   //      CLI CONFIG                                                                         //
//   //                                                                                             //
//   // =========================================================================================== //
// }
/** Primary source for reading and writing project config files
 * for the current context of the project.
 * That is: the project config and project-user config...
 * @param projRoot Fully qualified path to the folder containing the project declaration file from which to scope method calls for this class. */
let ProjectContextRepo = class ProjectContextRepo {
    constructor(projectEnviro) {
        this.projRoot = projectEnviro.projectRoot;
    }
    // Commented out bc moved to UserContextManagger in codiac-ops-enterprise
    // // =========================================================================================== //
    // //                                                                                             //
    // //      USER CONFIG                                                                         //
    // //                                                                                             //
    // // =========================================================================================== //
    // /** Attempts to load the user and all of their tenant tokens persisted locally by the Toyhauler CLI.  
    //  * Returns undefined for not found and throws any encountered exceptions. */
    // public loadUserContext(tenantCode: string): UserContext | undefined {
    //   // this.logger.trace(`Reading ${path.join("~/", LocalOps.CLI_CONFIG_FOLDER_NAME, LocalOps.USER_CONTEXT_FILENAME)}`)
    //   let context = JsonUtils.deserializeJsonFile<UserContext>(path.join("~/", DxConstants.CLI_CONFIG_FOLDER_NAME, DxConstants.USER_CONTEXT_FILENAME));
    //   // if (context) {
    //   //   this.logger.trace(`Current user context (from cache).  User: ${context.userName}, TenantCode: ${context.currentTenantCode}`)
    //   // }
    //   return context;
    // }
    // /** Writes the given UserContext to the Toyhauler user config folder on the local machine.  
    //  * TODO:  Consider writing this to the cache folder instead of the config folder. 
    //  * Throws any encountered exceptions. */
    // public writeUserContext(userContext: UserContext): void {
    //   let pathName = path.join("~/", DxConstants.CLI_CONFIG_FOLDER_NAME, DxConstants.USER_CONTEXT_FILENAME);
    //   // this.logger.debug(`Writing UserContext to ${pathName}`);
    //   JsonUtils.serializeJsonFile(userContext, pathName);
    // }
    // /** Persists the current user, its token, and its tenantCode to the user context 
    //  *  and the userContext file stored on the local machine. */
    // public async saveToUserContext(currentContext: UserContext | undefined, userName: string, token: string, tenantCode?: string, tokenExpiration?: Date): Promise<UserContext> {
    //   return new Promise<UserContext>(async (resolve, reject) => {
    //     try {
    //       // if (userName) {
    //         if (!currentContext) {  // wanna load it here?  this._cntx = await this.loadUserContext(user.tenantCode);
    //           currentContext = new UserContext(userName, tenantCode, token, tokenExpiration);
    //         } else {
    //           currentContext.userName = userName;
    //           currentContext.currentTenantCode = tenantCode;
    //           currentContext.currentToken = token;
    //           currentContext.tokenExpiration = tokenExpiration;
    //           if (tenantCode) currentContext.tokens[tenantCode] = token
    //         }
    //         await this.writeUserContext(currentContext);
    //       // } else {
    //       //   // null input - do nothing.
    //       //   TODO:  Consider either throwing an error here OR changing signature to return an undefined.
    //       // }
    //       resolve(currentContext);
    //     } catch (err) {
    //       reject(err);
    //     }
    //   });
    // }
    // =========================================================================================== //
    //                                                                                             //
    //      PROJECT CONFIG                                                                         //
    //                                                                                             //
    // =========================================================================================== //
    /** Deserializes the Toyhauler config file in scope for the current working directory.
     * Throws if none is defined up the folder tree. */
    readProjectConfig(folder) {
        let root = folder ? cli_path_walker_1.CliPathWalker.getProjectRoot(folder) : this.projRoot;
        let targetFile = path.join(root, ops_constants_1.OpsConstants.PROJECT_CONFIG_FILENAME);
        let contents = fs.readFileSync(targetFile, { encoding: "utf-8" });
        let raw = JSON.parse(contents); // this doesnt run the ctor.
        let config = Object.assign(new codiac_relay_contracts_1.ProjectConfig(raw.name, raw.tenantCode, dx_constants_1.DxConstants.DEFAULT_INIT_CODE_VERSION), raw);
        return config;
    }
    /** Instantiates a fresh config object with default values.
     * Assumes the project has been initialized.
     * @param apiName Friendly title for the api project (defaults to the name of the project folder)
     * @param tenantCode identifier for the tenant that owns this projeect.
    */
    createDefaultProjectConfig(apiName, tenantCode) {
        let actualName = apiName;
        if (!actualName) {
            // let folder = projectRoot.split(path.sep).pop();
            let folder = path.basename(this.projRoot);
            if (!folder)
                throw new Error("Your project does not appear to have a parent folder.  Please initialize your project in its own folder.");
            actualName = Case.kebab(folder);
        }
        let cfg = new codiac_relay_contracts_1.ProjectConfig(actualName, tenantCode || dx_constants_1.DxConstants.UNREGISTERED_TENANT_CODE, dx_constants_1.DxConstants.DEFAULT_INIT_CODE_VERSION);
        return cfg;
    }
    /** Serializes the given config to its file.  Throws if the project root hasnt been initialized. */
    updateProjectConfigFile(config) {
        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 pathName = path.join(this.projRoot, ops_constants_1.OpsConstants.PROJECT_CONFIG_FILENAME);
                    codiac_ops_common_1.JsonUtils.serializeJsonFile(config, pathName);
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** News up a project config object and serializes
     * to a file in the current working directory,
     * thus establishing it as a project root. */
    writeNewProjectConfig(seed) {
        let folder = process.cwd();
        let projectName = Case.kebab(path.basename(folder));
        let config = seed || new codiac_relay_contracts_1.ProjectConfig(projectName, dx_constants_1.DxConstants.UNREGISTERED_TENANT_CODE, dx_constants_1.DxConstants.DEFAULT_INIT_CODE_VERSION);
        let targetFile = path.join(folder, ops_constants_1.OpsConstants.PROJECT_CONFIG_FILENAME);
        // try {
        fs.writeFileSync(targetFile, JSON.stringify(config, undefined, '  '));
        // } catch (err) {
        //   this.log(`Error creating ${CONFIG_NAME}: ${err}`)
        // }
        return config;
    }
    // =========================================================================================== //
    //                                                                                             //
    //      PROJECT-USER CONFIG                                                                    //
    //                                                                                             //
    // =========================================================================================== //
    /** Reads the user-specific project config file, if it exists.
   * Otherwise returns a new empty instance.
   */
    readProjectUserConfig() {
        let projectRoot = this.projRoot; // || CliPathWalker.getProjectRoot();
        let userConfigFolder = path.join(projectRoot, ops_constants_1.OpsConstants.PROJECT_USER_CONFIG_FOLDER_NAME);
        let sourceFile = path.join(userConfigFolder, ops_constants_1.OpsConstants.PROJECT_USER_CONFIG_FILENAME);
        let config = new codiac_relay_contracts_1.ProjectUserConfig();
        if (fs.existsSync(sourceFile)) {
            let contents = fs.readFileSync(sourceFile, { encoding: "utf-8" });
            let raw = JSON.parse(contents); // this doesnt run the ctor.
            config = Object.assign(new codiac_relay_contracts_1.ProjectUserConfig(), raw);
        }
        return config;
    }
    /** Serializes the given config to a file in the project user folder. */
    writeProjectUserConfig(config) {
        let projectRoot = this.projRoot;
        let userConfigFolder = path.join(projectRoot, ops_constants_1.OpsConstants.PROJECT_USER_CONFIG_FOLDER_NAME);
        let targetFile = path.join(userConfigFolder, ops_constants_1.OpsConstants.PROJECT_USER_CONFIG_FILENAME);
        // try {
        if (!fs.existsSync(userConfigFolder)) {
            fs.mkdirSync(userConfigFolder, { recursive: true });
        }
        fs.writeFileSync(targetFile, JSON.stringify(config, undefined, '  '));
        // } catch (err) {
        //   this.log(`Error creating ${CONFIG_NAME}: ${err}`)
        // }
    }
};
ProjectContextRepo = tslib_1.__decorate([
    (0, inversify_1.injectable)(),
    tslib_1.__param(0, (0, inversify_1.inject)(entities_1.ProjectEnviro)),
    tslib_1.__metadata("design:paramtypes", [entities_1.ProjectEnviro])
], ProjectContextRepo);
exports.ProjectContextRepo = ProjectContextRepo;
//# sourceMappingURL=cli-context-repo.js.map