"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../constants");
const helpers_1 = require("../common/helpers");
const os_1 = require("os");
const decorators_1 = require("../common/decorators");
class PlatformEnvironmentRequirements {
    constructor($commandsService, $doctorService, $errors, $logger, $nativeScriptCloudExtensionService, $prompter, $staticConfig, $analyticsService, $injector, $playgroundQrCodeGenerator) {
        this.$commandsService = $commandsService;
        this.$doctorService = $doctorService;
        this.$errors = $errors;
        this.$logger = $logger;
        this.$nativeScriptCloudExtensionService = $nativeScriptCloudExtensionService;
        this.$prompter = $prompter;
        this.$staticConfig = $staticConfig;
        this.$analyticsService = $analyticsService;
        this.$injector = $injector;
        this.$playgroundQrCodeGenerator = $playgroundQrCodeGenerator;
        this.cliCommandToCloudCommandName = {
            "build": "tns cloud build",
            "run": "tns cloud run",
            "deploy": "tns cloud deploy"
        };
    }
    get $liveSyncService() {
        return this.$injector.resolve("liveSyncService");
    }
    checkEnvironmentRequirements(input) {
        return __awaiter(this, void 0, void 0, function* () {
            const { platform, projectDir, runtimeVersion } = input;
            const notConfiguredEnvOptions = input.notConfiguredEnvOptions || {};
            const options = input.options || {};
            let selectedOption = null;
            if (process.env.NS_SKIP_ENV_CHECK) {
                yield this.$analyticsService.trackEventActionInGoogleAnalytics({
                    action: "Check Environment Requirements",
                    additionalData: "Skipped: NS_SKIP_ENV_CHECK is set"
                });
                return {
                    canExecute: true,
                    selectedOption
                };
            }
            const canExecute = yield this.$doctorService.canExecuteLocalBuild(platform, projectDir, runtimeVersion);
            if (!canExecute) {
                if (!helpers_1.isInteractive()) {
                    yield this.$analyticsService.trackEventActionInGoogleAnalytics({
                        action: "Check Environment Requirements",
                        additionalData: "Non-interactive terminal, unable to execute local builds."
                    });
                    this.fail(this.getNonInteractiveConsoleMessage(platform));
                }
                const infoMessage = this.getInteractiveConsoleMessage(notConfiguredEnvOptions);
                const choices = this.getChoices(notConfiguredEnvOptions);
                selectedOption = yield this.promptForChoice({ infoMessage, choices });
                yield this.processCloudBuildsIfNeeded(selectedOption, platform);
                this.processManuallySetupIfNeeded(selectedOption, platform);
                yield this.processSyncToPreviewAppIfNeeded(selectedOption, projectDir, options);
                if (selectedOption === PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME) {
                    yield this.$doctorService.runSetupScript();
                    if (yield this.$doctorService.canExecuteLocalBuild(platform, projectDir, runtimeVersion)) {
                        return {
                            canExecute: true,
                            selectedOption
                        };
                    }
                    if (this.$nativeScriptCloudExtensionService.isInstalled()) {
                        const option = yield this.promptForChoice({
                            infoMessage: PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE,
                            choices: [
                                PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME,
                                PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME
                            ]
                        });
                        this.processTryCloudSetupIfNeeded(option, platform);
                        this.processManuallySetupIfNeeded(option, platform);
                    }
                    else {
                        const option = yield this.promptForChoice({
                            infoMessage: PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE,
                            choices: [
                                PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME,
                                PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME
                            ]
                        });
                        yield this.processCloudBuildsIfNeeded(option, platform);
                        this.processManuallySetupIfNeeded(option, platform);
                    }
                }
                if (selectedOption === PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME) {
                    yield this.processBothCloudBuildsAndSetupScript();
                    if (yield this.$doctorService.canExecuteLocalBuild(platform, projectDir, runtimeVersion)) {
                        return {
                            canExecute: true,
                            selectedOption
                        };
                    }
                    this.processManuallySetup(platform);
                }
                this.processTryCloudSetupIfNeeded(selectedOption, platform);
            }
            return {
                canExecute,
                selectedOption
            };
        });
    }
    processCloudBuildsIfNeeded(selectedOption, platform) {
        return __awaiter(this, void 0, void 0, function* () {
            if (selectedOption === PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME) {
                yield this.processCloudBuilds(platform);
            }
        });
    }
    processCloudBuilds(platform) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.processCloudBuildsCore();
            this.fail(this.getCloudBuildsMessage(platform));
        });
    }
    processCloudBuildsCore() {
        return this.$nativeScriptCloudExtensionService.install();
    }
    getCloudBuildsMessage(platform) {
        const cloudCommandName = this.cliCommandToCloudCommandName[(this.$commandsService.currentCommandData || {}).commandName];
        if (!cloudCommandName) {
            return `In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.`;
        }
        if (!platform) {
            return `Use the $ tns login command to log in with your account and then $ ${cloudCommandName.toLowerCase()} command.`;
        }
        return `Use the $ tns login command to log in with your account and then $ ${cloudCommandName.toLowerCase()} ${platform.toLowerCase()} command.`;
    }
    processTryCloudSetupIfNeeded(selectedOption, platform) {
        if (selectedOption === PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME) {
            this.fail(this.getCloudBuildsMessage(platform));
        }
    }
    processManuallySetupIfNeeded(selectedOption, platform) {
        if (selectedOption === PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME) {
            this.processManuallySetup(platform);
        }
    }
    processSyncToPreviewAppIfNeeded(selectedOption, projectDir, options) {
        return __awaiter(this, void 0, void 0, function* () {
            if (selectedOption === PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_OPTION_NAME) {
                if (!projectDir) {
                    this.$errors.failWithoutHelp(`No project found. In order to sync to playground you need to go to project directory or specify --path option.`);
                }
                yield this.$liveSyncService.liveSync([], {
                    syncToPreviewApp: true,
                    projectDir,
                    skipWatcher: !options.watch,
                    watchAllFiles: options.syncAllFiles,
                    clean: options.clean,
                    bundle: !!options.bundle,
                    release: options.release,
                    env: options.env,
                    timeout: options.timeout,
                    useHotModuleReload: options.hmr
                });
                yield this.$playgroundQrCodeGenerator.generateQrCode({ useHotModuleReload: options.hmr, link: options.link });
            }
        });
    }
    processManuallySetup(platform) {
        this.fail(`To be able to ${platform ? `build for ${platform}` : 'build'}, verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}. If you have any questions, check Stack Overflow: 'https://stackoverflow.com/questions/tagged/nativescript' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'`);
    }
    processBothCloudBuildsAndSetupScript() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                yield this.processCloudBuildsCore();
            }
            catch (e) {
                this.$logger.trace(`Error while installing ${constants_1.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension. ${e.message}.`);
            }
            yield this.$doctorService.runSetupScript();
        });
    }
    fail(message) {
        this.$errors.fail({ formatStr: message, suppressCommandHelp: true, printOnStdout: true });
    }
    getNonInteractiveConsoleMessage(platform) {
        return this.$nativeScriptCloudExtensionService.isInstalled() ?
            this.buildMultilineMessage([
                `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`,
                PlatformEnvironmentRequirements.RUN_PREVIEW_COMMAND_MESSAGE,
                PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE,
                this.getCloudBuildsMessage(platform),
                this.getEnvVerificationMessage()
            ]) :
            this.buildMultilineMessage([
                PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE,
                PlatformEnvironmentRequirements.RUN_PREVIEW_COMMAND_MESSAGE,
                PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE,
                `Run $ tns cloud setup command to install the ${constants_1.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.`,
                this.getEnvVerificationMessage()
            ]);
    }
    getInteractiveConsoleMessage(options) {
        const isNativeScriptCloudExtensionInstalled = this.$nativeScriptCloudExtensionService.isInstalled();
        const message = isNativeScriptCloudExtensionInstalled ?
            `${PlatformEnvironmentRequirements.MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}` :
            PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE;
        const choices = isNativeScriptCloudExtensionInstalled ? [
            `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`,
            `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.`
        ] : [
            `Select "Configure for Cloud Builds" to install the ${constants_1.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`,
            `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`,
            `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`,
            `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`
        ];
        if (!options.hideSyncToPreviewAppOption) {
            choices.unshift(PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_MESSAGE);
        }
        const lines = [message].concat(choices);
        const result = this.buildMultilineMessage(lines);
        return result;
    }
    promptForChoice(opts) {
        return __awaiter(this, void 0, void 0, function* () {
            this.$logger.info(opts.infoMessage);
            yield this.$analyticsService.trackEventActionInGoogleAnalytics({
                action: "Check Environment Requirements",
                additionalData: `User should select: ${opts.infoMessage}`
            });
            const selection = yield this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, opts.choices);
            yield this.$analyticsService.trackEventActionInGoogleAnalytics({
                action: "Check Environment Requirements",
                additionalData: `User selected: ${selection}`
            });
            return selection;
        });
    }
    getEnvVerificationMessage() {
        return `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`;
    }
    buildMultilineMessage(parts) {
        return parts.join(os_1.EOL);
    }
    getChoices(options) {
        const choices = [];
        if (this.$nativeScriptCloudExtensionService.isInstalled()) {
            choices.push(...[PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME,
                PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME]);
            if (!options.hideCloudBuildOption) {
                choices.unshift(PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME);
            }
        }
        else {
            choices.push(...[
                PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME,
                PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME,
                PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME,
                PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME,
            ]);
        }
        if (!options.hideSyncToPreviewAppOption) {
            choices.unshift(PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_OPTION_NAME);
        }
        return choices;
    }
}
PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME = "Configure for Cloud Builds";
PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME = "Configure for Local Builds";
PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME = "Try Cloud Operation";
PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_OPTION_NAME = "Sync to Playground";
PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME = "Skip Step and Configure Manually";
PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME = "Configure for Both Local and Cloud Builds";
PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE = "To continue, choose one of the following options: ";
PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = `The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. Please consult our setup instructions here 'https://docs.nativescript.org/start/quick-setup'.`;
PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE = "Your environment is not configured properly and you will not be able to execute local builds.";
PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants_1.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. ${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE} `;
PlatformEnvironmentRequirements.MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE = `You have ${constants_1.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension installed, so you can execute cloud builds, but ${_.lowerFirst(PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE)}`;
PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE = 'Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.';
PlatformEnvironmentRequirements.SYNC_TO_PREVIEW_APP_MESSAGE = `Select "Sync to Playground" to enjoy NativeScript without any local setup. All you need is a couple of companion apps installed on your devices.`;
PlatformEnvironmentRequirements.RUN_PREVIEW_COMMAND_MESSAGE = `Run $ tns preview command to enjoy NativeScript without any local setup.`;
__decorate([
    decorators_1.cache()
], PlatformEnvironmentRequirements.prototype, "$liveSyncService", null);
exports.PlatformEnvironmentRequirements = PlatformEnvironmentRequirements;
$injector.register("platformEnvironmentRequirements", PlatformEnvironmentRequirements);
