"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.LiveSyncCommandHelper = void 0;
const constants_1 = require("../constants");
const yok_1 = require("../common/yok");
const _ = require("lodash");
class LiveSyncCommandHelper {
    constructor($androidBundleValidatorHelper, $buildDataService, $projectData, $options, $deployController, $iosDeviceOperations, $mobileHelper, $devicesService, $injector, $buildController, $analyticsService, $errors, $iOSSimulatorLogProvider, $cleanupService, $runController) {
        this.$androidBundleValidatorHelper = $androidBundleValidatorHelper;
        this.$buildDataService = $buildDataService;
        this.$projectData = $projectData;
        this.$options = $options;
        this.$deployController = $deployController;
        this.$iosDeviceOperations = $iosDeviceOperations;
        this.$mobileHelper = $mobileHelper;
        this.$devicesService = $devicesService;
        this.$injector = $injector;
        this.$buildController = $buildController;
        this.$analyticsService = $analyticsService;
        this.$errors = $errors;
        this.$iOSSimulatorLogProvider = $iOSSimulatorLogProvider;
        this.$cleanupService = $cleanupService;
        this.$runController = $runController;
    }
    get $platformsDataService() {
        return this.$injector.resolve("platformsDataService");
    }
    getLiveSyncData(projectDir) {
        const liveSyncInfo = {
            projectDir,
            skipWatcher: !this.$options.watch || this.$options.justlaunch,
            clean: this.$options.clean,
            release: this.$options.release,
            env: this.$options.env,
            timeout: this.$options.timeout,
            useHotModuleReload: this.$options.hmr,
            force: this.$options.force,
            emulator: this.$options.emulator,
        };
        return liveSyncInfo;
    }
    getDeviceInstances(platform) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.$devicesService.initialize({
                platform,
                deviceId: this.$options.device,
                emulator: this.$options.emulator,
                skipInferPlatform: !platform,
                sdk: this.$options.sdk,
            });
            const devices = this.$devicesService
                .getDeviceInstances()
                .filter((d) => !platform ||
                d.deviceInfo.platform.toLowerCase() === platform.toLowerCase());
            return devices;
        });
    }
    createDeviceDescriptors(devices, platform, additionalOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            const deviceDescriptors = devices.map((device) => {
                const outputPath = additionalOptions &&
                    additionalOptions.getOutputDirectory &&
                    additionalOptions.getOutputDirectory({
                        platform: device.deviceInfo.platform,
                        emulator: device.isEmulator,
                        projectDir: this.$projectData.projectDir,
                    });
                const buildData = this.$buildDataService.getBuildData(this.$projectData.projectDir, device.deviceInfo.platform, Object.assign(Object.assign({}, this.$options.argv), { outputPath, buildForDevice: !device.isEmulator, watch: !this.$options.release && this.$options.watch, _device: device }));
                this.$androidBundleValidatorHelper.validateDeviceApiLevel(device, buildData);
                const buildAction = additionalOptions && additionalOptions.buildPlatform
                    ? additionalOptions.buildPlatform.bind(additionalOptions.buildPlatform, device.deviceInfo.platform, buildData, this.$projectData)
                    : this.$buildController.build.bind(this.$buildController, buildData);
                const info = {
                    identifier: device.deviceInfo.identifier,
                    buildAction,
                    debuggingEnabled: additionalOptions &&
                        additionalOptions.deviceDebugMap &&
                        additionalOptions.deviceDebugMap[device.deviceInfo.identifier],
                    debugOptions: this.$options,
                    skipNativePrepare: additionalOptions && additionalOptions.skipNativePrepare,
                    buildData,
                };
                return info;
            });
            return deviceDescriptors;
        });
    }
    getPlatformsForOperation(platform) {
        const availablePlatforms = platform
            ? [platform]
            : _.values(this.$mobileHelper.platformNames.map((p) => p.toLowerCase()));
        return availablePlatforms;
    }
    executeCommandLiveSync(platform, additionalOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            const devices = yield this.getDeviceInstances(platform);
            yield this.executeLiveSyncOperation(devices, platform, additionalOptions);
        });
    }
    executeLiveSyncOperation(devices, platform, additionalOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            const { liveSyncInfo, deviceDescriptors } = yield this.executeLiveSyncOperationCore(devices, platform, additionalOptions);
            if (this.$options.release) {
                yield this.runInRelease(platform, deviceDescriptors);
                return;
            }
            yield this.$runController.run({
                liveSyncInfo,
                deviceDescriptors,
            });
            const remainingDevicesToSync = devices.map((d) => d.deviceInfo.identifier);
            this.$runController.on(constants_1.RunOnDeviceEvents.runOnDeviceStopped, (data) => {
                _.remove(remainingDevicesToSync, (d) => d === data.deviceIdentifier);
                if (remainingDevicesToSync.length === 0) {
                    process.exit(134);
                }
            });
        });
    }
    validatePlatform(platform) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = {};
            const availablePlatforms = this.getPlatformsForOperation(platform);
            for (const availablePlatform of availablePlatforms) {
                const platformData = this.$platformsDataService.getPlatformData(availablePlatform, this.$projectData);
                const platformProjectService = platformData.platformProjectService;
                const validateOutput = yield platformProjectService.validate(this.$projectData, this.$options);
                result[availablePlatform.toLowerCase()] = validateOutput;
            }
            return result;
        });
    }
    executeLiveSyncOperationCore(devices, platform, additionalOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!devices || !devices.length) {
                if (platform) {
                    this.$errors.fail("Unable to find applicable devices to execute operation. Ensure connected devices are trusted and try again.");
                }
                else {
                    this.$errors.fail("Unable to find applicable devices to execute operation and unable to start emulator when platform is not specified.");
                }
            }
            const workingWithAppleDevices = !platform || this.$mobileHelper.isApplePlatfrom(platform);
            const shouldKeepProcessAlive = this.$options.watch || !this.$options.justlaunch;
            if (shouldKeepProcessAlive) {
                this.$analyticsService.setShouldDispose(false);
                this.$cleanupService.setShouldDispose(false);
                if (workingWithAppleDevices) {
                    this.$iosDeviceOperations.setShouldDispose(false);
                    this.$iOSSimulatorLogProvider.setShouldDispose(false);
                }
            }
            const deviceDescriptors = yield this.createDeviceDescriptors(devices, platform, additionalOptions);
            const liveSyncInfo = this.getLiveSyncData(this.$projectData.projectDir);
            return { liveSyncInfo, deviceDescriptors };
        });
    }
    runInRelease(platform, deviceDescriptors) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.$devicesService.initialize({
                platform,
                deviceId: this.$options.device,
                emulator: this.$options.emulator,
                skipInferPlatform: !platform,
                sdk: this.$options.sdk,
            });
            yield this.$deployController.deploy({ deviceDescriptors });
            for (const deviceDescriptor of deviceDescriptors) {
                const device = this.$devicesService.getDeviceByIdentifier(deviceDescriptor.identifier);
                yield device.applicationManager.startApplication({
                    appId: this.$projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()],
                    projectName: this.$projectData.projectName,
                    projectDir: this.$projectData.projectDir,
                });
            }
        });
    }
}
exports.LiveSyncCommandHelper = LiveSyncCommandHelper;
yok_1.injector.register("liveSyncCommandHelper", LiveSyncCommandHelper);
