"use strict";
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";
    }
    async execute(args) {
        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);
        this.ensurePackageDir(projectDir);
        try {
            await this.downloadPackage(selectedTemplate, projectDir);
            await this.setupSeed(projectDir, pluginRepoName);
        }
        catch (err) {
            this.$fs.deleteDirectory(projectDir);
            throw err;
        }
        this.$logger.printMarkdown("Solution for `%s` was successfully created.", pluginRepoName);
    }
    async canExecute(args) {
        if (!args[0]) {
            this.$errors.failWithHelp("You must specify the plugin repository name.");
        }
        return true;
    }
    async setupSeed(projectDir, pluginRepoName) {
        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 };
            await this.$packageManager.install(cwd, cwd, npmOptions);
        }
        finally {
            spinner.stop();
        }
        const gitHubUsername = await this.getGitHubUsername(config.username);
        const pluginNameSource = await this.getPluginNameSource(config.pluginName, pluginRepoName);
        const includeTypescriptDemo = await this.getShouldIncludeDemoResult(config.includeTypeScriptDemo, this.includeTypeScriptDemoMessage);
        const includeAngularDemo = await 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.");
        }
        const pathToPostCloneScript = path.join("scripts", "postclone");
        const params = [
            pathToPostCloneScript,
            `gitHubUsername=${gitHubUsername}`,
            `pluginName=${pluginNameSource}`,
            "initGit=y",
            `includeTypeScriptDemo=${includeTypescriptDemo}`,
            `includeAngularDemo=${includeAngularDemo}`,
        ];
        const outputScript = await 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);
        }
    }
    async downloadPackage(selectedTemplate, projectDir) {
        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();
            await this.$pacoteService.extractPackage(packageToInstall, projectDir);
        }
        finally {
            spinner.stop();
        }
    }
    async getGitHubUsername(gitHubUsername) {
        if (!gitHubUsername) {
            gitHubUsername = "NativeScriptDeveloper";
            if ((0, helpers_1.isInteractive)()) {
                gitHubUsername = await this.$prompter.getString(this.userMessage, {
                    allowEmpty: false,
                    defaultAction: () => {
                        return gitHubUsername;
                    },
                });
            }
        }
        return gitHubUsername;
    }
    async getPluginNameSource(pluginNameSource, pluginRepoName) {
        if (!pluginNameSource) {
            const prefix = "nativescript-";
            pluginNameSource = pluginRepoName.toLowerCase().startsWith(prefix)
                ? pluginRepoName.slice(prefix.length, pluginRepoName.length)
                : pluginRepoName;
            if ((0, helpers_1.isInteractive)()) {
                pluginNameSource = await this.$prompter.getString(this.nameMessage, {
                    allowEmpty: false,
                    defaultAction: () => {
                        return pluginNameSource;
                    },
                });
            }
        }
        return pluginNameSource;
    }
    async getShouldIncludeDemoResult(includeDemoOption, message) {
        let shouldIncludeDemo = !!includeDemoOption;
        if (!includeDemoOption && (0, helpers_1.isInteractive)()) {
            shouldIncludeDemo = await this.$prompter.confirm(message, () => {
                return true;
            });
        }
        return shouldIncludeDemo ? "y" : "n";
    }
}
exports.CreatePluginCommand = CreatePluginCommand;
yok_1.injector.registerCommand(["plugin|create"], CreatePluginCommand);
