"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuestionMark = exports.N = exports.C = exports.W = exports.CtrlC = exports.ShiftR = exports.R = exports.OpenVisionOSCommand = exports.ShiftV = exports.V = exports.OpenIOSCommand = exports.ShiftI = exports.I = exports.OpenAndroidCommand = exports.ShiftA = exports.A = void 0;
const fs = require("fs");
const os_1 = require("os");
const path = require("path");
const color_1 = require("../color");
const yok_1 = require("../common/yok");
class A {
    constructor($startService) {
        this.$startService = $startService;
        this.key = "a";
        this.platform = "Android";
        this.description = "Run Android app";
        this.group = "Android";
    }
    async execute() {
        this.$startService.runAndroid();
    }
    canExecute(processType) {
        return processType === "start";
    }
}
exports.A = A;
class ShiftA {
    constructor($logger, $liveSyncCommandHelper, $childProcess, $projectData) {
        this.$logger = $logger;
        this.$liveSyncCommandHelper = $liveSyncCommandHelper;
        this.$childProcess = $childProcess;
        this.$projectData = $projectData;
        this.key = "A";
        this.platform = "Android";
        this.description = "Open project in Android Studio";
        this.group = "Android";
        this.willBlockKeyCommandExecution = true;
        this.isInteractive = true;
    }
    getAndroidStudioPath() {
        const os = (0, os_1.platform)();
        if (os === "darwin") {
            const possibleStudioPaths = [
                "/Applications/Android Studio.app",
                `${process.env.HOME}/Applications/Android Studio.app`,
            ];
            return possibleStudioPaths.find((p) => fs.existsSync(p)) || null;
        }
        else if (os === "win32") {
            const studioPath = path.join("C:", "Program Files", "Android", "Android Studio", "bin", "studio64.exe");
            return fs.existsSync(studioPath) ? studioPath : null;
        }
        else if (os === "linux") {
            const studioPath = "/usr/local/android-studio/bin/studio.sh";
            return fs.existsSync(studioPath) ? studioPath : null;
        }
        return null;
    }
    async execute() {
        this.$liveSyncCommandHelper.validatePlatform(this.platform);
        this.$projectData.initializeProjectData();
        const androidDir = `${this.$projectData.platformsDir}/android`;
        if (!fs.existsSync(androidDir)) {
            const prepareCommand = yok_1.injector.resolveCommand("prepare");
            await prepareCommand.execute([this.platform]);
            if (this.isInteractive) {
                process.stdin.resume();
            }
        }
        let studioPath = null;
        studioPath = process.env.NATIVESCRIPT_ANDROID_STUDIO_PATH;
        if (!studioPath) {
            studioPath = this.getAndroidStudioPath();
            if (!studioPath) {
                this.$logger.error("Android Studio is not installed, or is not in a standard location. Use NATIVESCRIPT_ANDROID_STUDIO_PATH.");
                return;
            }
        }
        const os = (0, os_1.platform)();
        if (os === "darwin") {
            this.$childProcess.exec(`open -a "${studioPath}" ${androidDir}`);
        }
        else if (os === "win32") {
            const child = this.$childProcess.spawn(studioPath, [androidDir], {
                detached: true,
                stdio: "ignore",
            });
            child.unref();
        }
        else if (os === "linux") {
            this.$childProcess.exec(`${studioPath} ${androidDir}`);
        }
    }
}
exports.ShiftA = ShiftA;
class OpenAndroidCommand extends ShiftA {
    constructor($logger, $liveSyncCommandHelper, $childProcess, $projectData, $options) {
        super($logger, $liveSyncCommandHelper, $childProcess, $projectData);
        this.$options = $options;
        this.isInteractive = false;
    }
    async execute() {
        this.$options.watch = false;
        super.execute();
    }
}
exports.OpenAndroidCommand = OpenAndroidCommand;
class I {
    constructor($startService) {
        this.$startService = $startService;
        this.key = "i";
        this.platform = "iOS";
        this.description = "Run iOS app";
        this.group = "iOS";
    }
    async execute() {
        this.$startService.runIOS();
    }
    canExecute(processType) {
        return processType === "start";
    }
}
exports.I = I;
class ShiftI {
    constructor($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService) {
        this.$iOSProjectService = $iOSProjectService;
        this.$logger = $logger;
        this.$childProcess = $childProcess;
        this.$projectData = $projectData;
        this.$xcodeSelectService = $xcodeSelectService;
        this.$xcodebuildArgsService = $xcodebuildArgsService;
        this.key = "I";
        this.platform = "iOS";
        this.description = "Open project in Xcode";
        this.group = "iOS";
        this.willBlockKeyCommandExecution = true;
        this.isInteractive = true;
    }
    async execute() {
        const os = (0, os_1.platform)();
        if (os === "darwin") {
            this.$projectData.initializeProjectData();
            const iosDir = path.resolve(this.$projectData.platformsDir, "ios");
            if (!fs.existsSync(iosDir)) {
                const prepareCommand = yok_1.injector.resolveCommand("prepare");
                await prepareCommand.execute(["ios"]);
                if (this.isInteractive) {
                    process.stdin.resume();
                }
            }
            const platformData = this.$iOSProjectService.getPlatformData(this.$projectData);
            const xcprojectFile = this.$xcodebuildArgsService.getXcodeProjectArgs(platformData, this.$projectData)[1];
            if (fs.existsSync(xcprojectFile)) {
                this.$xcodeSelectService
                    .getDeveloperDirectoryPath()
                    .then(() => this.$childProcess.exec(`open ${xcprojectFile}`, {}))
                    .catch((e) => {
                    this.$logger.error(e.message);
                });
            }
            else {
                this.$logger.error(`Unable to open project file: ${xcprojectFile}`);
            }
        }
        else {
            this.$logger.error("Opening a project in XCode requires macOS.");
        }
    }
}
exports.ShiftI = ShiftI;
class OpenIOSCommand extends ShiftI {
    constructor($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService, $options) {
        super($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService);
        this.$options = $options;
        this.isInteractive = false;
    }
    async execute() {
        this.$options.watch = false;
        super.execute();
    }
}
exports.OpenIOSCommand = OpenIOSCommand;
class V {
    constructor($startService) {
        this.$startService = $startService;
        this.key = "v";
        this.platform = "visionOS";
        this.description = "Run visionOS app";
        this.group = "visionOS";
    }
    async execute() {
        this.$startService.runVisionOS();
    }
    canExecute(processType) {
        return processType === "start";
    }
}
exports.V = V;
class ShiftV {
    constructor($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService, $options) {
        this.$iOSProjectService = $iOSProjectService;
        this.$logger = $logger;
        this.$childProcess = $childProcess;
        this.$projectData = $projectData;
        this.$xcodeSelectService = $xcodeSelectService;
        this.$xcodebuildArgsService = $xcodebuildArgsService;
        this.$options = $options;
        this.key = "V";
        this.platform = "visionOS";
        this.description = "Open project in Xcode";
        this.group = "visionOS";
        this.willBlockKeyCommandExecution = true;
        this.isInteractive = true;
    }
    async execute() {
        this.$options.platformOverride = "visionOS";
        const os = (0, os_1.platform)();
        if (os === "darwin") {
            this.$projectData.initializeProjectData();
            const visionOSDir = path.resolve(this.$projectData.platformsDir, "visionos");
            if (!fs.existsSync(visionOSDir)) {
                const prepareCommand = yok_1.injector.resolveCommand("prepare");
                await prepareCommand.execute(["visionos"]);
                if (this.isInteractive) {
                    process.stdin.resume();
                }
            }
            const platformData = this.$iOSProjectService.getPlatformData(this.$projectData);
            const xcprojectFile = this.$xcodebuildArgsService.getXcodeProjectArgs(platformData, this.$projectData)[1];
            if (fs.existsSync(xcprojectFile)) {
                this.$xcodeSelectService
                    .getDeveloperDirectoryPath()
                    .then(() => this.$childProcess.exec(`open ${xcprojectFile}`, {}))
                    .catch((e) => {
                    this.$logger.error(e.message);
                });
            }
            else {
                this.$logger.error(`Unable to open project file: ${xcprojectFile}`);
            }
        }
        else {
            this.$logger.error("Opening a project in XCode requires macOS.");
        }
        this.$options.platformOverride = null;
    }
}
exports.ShiftV = ShiftV;
class OpenVisionOSCommand extends ShiftV {
    constructor($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService, $options) {
        super($iOSProjectService, $logger, $childProcess, $projectData, $xcodeSelectService, $xcodebuildArgsService, $options);
        this.$options = $options;
        this.isInteractive = false;
    }
    async execute() {
        this.$options.watch = false;
        super.execute();
    }
}
exports.OpenVisionOSCommand = OpenVisionOSCommand;
class R {
    constructor($liveSyncCommandHelper) {
        this.$liveSyncCommandHelper = $liveSyncCommandHelper;
        this.key = "r";
        this.platform = "all";
        this.description = "Rebuild native app if needed and restart";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute(platform) {
        const devices = await this.$liveSyncCommandHelper.getDeviceInstances(platform);
        await this.$liveSyncCommandHelper.executeLiveSyncOperation(devices, platform, {
            restartLiveSync: true,
        });
    }
}
exports.R = R;
class ShiftR {
    constructor($liveSyncCommandHelper) {
        this.$liveSyncCommandHelper = $liveSyncCommandHelper;
        this.key = "R";
        this.platform = "all";
        this.description = "Force rebuild native app and restart";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute(platform) {
        const devices = await this.$liveSyncCommandHelper.getDeviceInstances(platform);
        await this.$liveSyncCommandHelper.executeLiveSyncOperation(devices, platform, {
            skipNativePrepare: false,
            forceRebuildNativeApp: true,
            restartLiveSync: true,
        });
    }
}
exports.ShiftR = ShiftR;
class CtrlC {
    constructor() {
        this.key = "\u0003";
        this.platform = "all";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = false;
    }
    async execute() {
        process.exit();
    }
}
exports.CtrlC = CtrlC;
class W {
    constructor($prepareController) {
        this.$prepareController = $prepareController;
        this.key = "w";
        this.platform = "all";
        this.description = "Toggle file watcher";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute() {
        try {
            const paused = await this.$prepareController.toggleFileWatcher();
            process.stdout.write(paused
                ? color_1.color.gray("Paused watching file changes... Press 'w' to resume.")
                : color_1.color.bgGreen("Resumed watching file changes"));
        }
        catch (e) { }
    }
}
exports.W = W;
class C {
    constructor($childProcess, $liveSyncCommandHelper) {
        this.$childProcess = $childProcess;
        this.$liveSyncCommandHelper = $liveSyncCommandHelper;
        this.key = "c";
        this.platform = "all";
        this.description = "Clean project";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute() {
        await this.$liveSyncCommandHelper.stop();
        const clean = this.$childProcess.spawn("ns", ["clean"]);
        clean.stdout.on("data", (data) => {
            process.stdout.write(data);
            if (data.toString().includes("Project successfully cleaned.") ||
                data.toString().includes("Project unsuccessfully cleaned.")) {
                clean.kill("SIGINT");
            }
        });
    }
}
exports.C = C;
class N {
    constructor() {
        this.key = "n";
        this.platform = "all";
        this.description = "Install dependencies";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute(platform) {
        const install = yok_1.injector.resolveCommand("install");
        await install.execute([]);
        process.stdin.resume();
    }
}
exports.N = N;
class QuestionMark {
    constructor($keyCommandHelper) {
        this.$keyCommandHelper = $keyCommandHelper;
        this.key = "?";
        this.platform = "all";
        this.description = "Show this help";
        this.group = "Development Workflow";
        this.willBlockKeyCommandExecution = true;
    }
    async execute(platform_) {
        let platform;
        switch (platform_.toLowerCase()) {
            case "android":
                platform = "Android";
                break;
            case "ios":
                platform = "iOS";
                break;
            case "visionOS":
            case "vision":
                platform = "visionOS";
                break;
            default:
                platform = "all";
                break;
        }
        this.$keyCommandHelper.printCommands(platform);
        process.stdin.resume();
    }
}
exports.QuestionMark = QuestionMark;
yok_1.injector.registerKeyCommand("a", A);
yok_1.injector.registerKeyCommand("A", ShiftA);
yok_1.injector.registerKeyCommand("i", I);
yok_1.injector.registerKeyCommand("I", ShiftI);
yok_1.injector.registerKeyCommand("v", V);
yok_1.injector.registerKeyCommand("V", ShiftV);
yok_1.injector.registerKeyCommand("r", R);
yok_1.injector.registerKeyCommand("R", ShiftR);
yok_1.injector.registerKeyCommand("w", W);
yok_1.injector.registerKeyCommand("c", C);
yok_1.injector.registerKeyCommand("A", ShiftA);
yok_1.injector.registerKeyCommand("n", N);
yok_1.injector.registerKeyCommand("?", QuestionMark);
yok_1.injector.registerKeyCommand("\u0003", CtrlC);
yok_1.injector.registerCommand("open|ios", OpenIOSCommand);
yok_1.injector.registerCommand("open|visionos", OpenVisionOSCommand);
yok_1.injector.registerCommand("open|vision", OpenVisionOSCommand);
yok_1.injector.registerCommand("open|android", OpenAndroidCommand);
