"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreatePluginCommand = void 0;
const path = require("path");
const helpers_1 = require("../../common/helpers");
const yok_1 = require("../../common/yok");
class CreatePluginCommand {
    constructor($options, $errors, $terminalSpinnerService, $logger, $pacoteService, $fs, $childProcess, $prompter, $packageManager) {
        this.$options = $options;
        this.$errors = $errors;
        this.$terminalSpinnerService = $terminalSpinnerService;
        this.$logger = $logger;
        this.$pacoteService = $pacoteService;
        this.$fs = $fs;
        this.$childProcess = $childProcess;
        this.$prompter = $prompter;
        this.$packageManager = $packageManager;
        this.allowedParameters = [];
        this.userMessage = "What is your GitHub username?\n(will be used to update the Github URLs in the plugin's package.json)";
        this.nameMessage = "What will be the name of your plugin?\n(use lowercase characters and dashes only)";
        this.includeTypeScriptDemoMessage = 'Do you want to include a "TypeScript NativeScript" application linked with your plugin to make development easier?';
        this.includeAngularDemoMessage = 'Do you want to include an "Angular NativeScript" application linked with your plugin to make development easier?';
        this.pathAlreadyExistsMessageTemplate = "Path already exists and is not empty %s";
    }
    execute(args) {
        return __awaiter(this, void 0, void 0, function* () {
            const pluginRepoName = args[0];
            const pathToProject = this.$options.path;
            const selectedTemplate = this.$options.template;
            const selectedPath = path.resolve(pathToProject || ".");
            const projectDir = path.join(selectedPath, pluginRepoName);
            // Must be out of try catch block, because will throw error if folder alredy exists and we don't want to delete it.
            this.ensurePackageDir(projectDir);
            try {
                yield this.downloadPackage(selectedTemplate, projectDir);
                yield this.setupSeed(projectDir, pluginRepoName);
            }
            catch (err) {
                // The call to this.ensurePackageDir() above will throw error if folder alredy exists, so it is safe to delete here.
                this.$fs.deleteDirectory(projectDir);
                throw err;
            }
            this.$logger.printMarkdown("Solution for `%s` was successfully created.", pluginRepoName);
        });
    }
    canExecute(args) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!args[0]) {
                this.$errors.failWithHelp("You must specify the plugin repository name.");
            }
            return true;
        });
    }
    setupSeed(projectDir, pluginRepoName) {
        return __awaiter(this, void 0, void 0, function* () {
            this.$logger.printMarkdown("Executing initial plugin configuration script...");
            const config = this.$options;
            const spinner = this.$terminalSpinnerService.createSpinner();
            const cwd = path.join(projectDir, "src");
            try {
                spinner.start();
                const npmOptions = { silent: true };
                yield this.$packageManager.install(cwd, cwd, npmOptions);
            }
            finally {
                spinner.stop();
            }
            const gitHubUsername = yield this.getGitHubUsername(config.username);
            const pluginNameSource = yield this.getPluginNameSource(config.pluginName, pluginRepoName);
            const includeTypescriptDemo = yield this.getShouldIncludeDemoResult(config.includeTypeScriptDemo, this.includeTypeScriptDemoMessage);
            const includeAngularDemo = yield this.getShouldIncludeDemoResult(config.includeAngularDemo, this.includeAngularDemoMessage);
            if (!(0, helpers_1.isInteractive)() &&
                (!config.username ||
                    !config.pluginName ||
                    !config.includeAngularDemo ||
                    !config.includeTypeScriptDemo)) {
                this.$logger.printMarkdown("Using default values for plugin creation options since your shell is not interactive.");
            }
            // run postclone script manually and kill it if it takes more than 10 sec
            const pathToPostCloneScript = path.join("scripts", "postclone");
            const params = [
                pathToPostCloneScript,
                `gitHubUsername=${gitHubUsername}`,
                `pluginName=${pluginNameSource}`,
                "initGit=y",
                `includeTypeScriptDemo=${includeTypescriptDemo}`,
                `includeAngularDemo=${includeAngularDemo}`,
            ];
            const outputScript = yield this.$childProcess.spawnFromEvent(process.execPath, params, "close", { stdio: "inherit", cwd, timeout: 10000 });
            if (outputScript && outputScript.stdout) {
                this.$logger.printMarkdown(outputScript.stdout);
            }
        });
    }
    ensurePackageDir(projectDir) {
        this.$fs.createDirectory(projectDir);
        if (this.$fs.exists(projectDir) && !this.$fs.isEmptyDir(projectDir)) {
            this.$errors.fail(this.pathAlreadyExistsMessageTemplate, projectDir);
        }
    }
    downloadPackage(selectedTemplate, projectDir) {
        return __awaiter(this, void 0, void 0, function* () {
            if (selectedTemplate) {
                this.$logger.printMarkdown("Make sure your custom template is compatible with the Plugin Seed at https://github.com/NativeScript/nativescript-plugin-seed/");
            }
            else {
                this.$logger.printMarkdown("Downloading the latest version of NativeScript Plugin Seed...");
            }
            const spinner = this.$terminalSpinnerService.createSpinner();
            const packageToInstall = selectedTemplate ||
                "https://github.com/NativeScript/nativescript-plugin-seed/archive/master.tar.gz";
            try {
                spinner.start();
                yield this.$pacoteService.extractPackage(packageToInstall, projectDir);
            }
            finally {
                spinner.stop();
            }
        });
    }
    getGitHubUsername(gitHubUsername) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!gitHubUsername) {
                gitHubUsername = "NativeScriptDeveloper";
                if ((0, helpers_1.isInteractive)()) {
                    gitHubUsername = yield this.$prompter.getString(this.userMessage, {
                        allowEmpty: false,
                        defaultAction: () => {
                            return gitHubUsername;
                        },
                    });
                }
            }
            return gitHubUsername;
        });
    }
    getPluginNameSource(pluginNameSource, pluginRepoName) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!pluginNameSource) {
                // remove nativescript- prefix for naming plugin files
                const prefix = "nativescript-";
                pluginNameSource = pluginRepoName.toLowerCase().startsWith(prefix)
                    ? pluginRepoName.slice(prefix.length, pluginRepoName.length)
                    : pluginRepoName;
                if ((0, helpers_1.isInteractive)()) {
                    pluginNameSource = yield this.$prompter.getString(this.nameMessage, {
                        allowEmpty: false,
                        defaultAction: () => {
                            return pluginNameSource;
                        },
                    });
                }
            }
            return pluginNameSource;
        });
    }
    getShouldIncludeDemoResult(includeDemoOption, message) {
        return __awaiter(this, void 0, void 0, function* () {
            let shouldIncludeDemo = !!includeDemoOption;
            if (!includeDemoOption && (0, helpers_1.isInteractive)()) {
                shouldIncludeDemo = yield this.$prompter.confirm(message, () => {
                    return true;
                });
            }
            return shouldIncludeDemo ? "y" : "n";
        });
    }
}
exports.CreatePluginCommand = CreatePluginCommand;
yok_1.injector.registerCommand(["plugin|create"], CreatePluginCommand);
//# sourceMappingURL=create-plugin.js.map