"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AndroidDeviceSocketsLiveSyncService = void 0;
const android_device_livesync_service_base_1 = require("./android-device-livesync-service-base");
const constants_1 = require("../../common/constants");
const android_livesync_tool_1 = require("./android-livesync-tool");
const path = require("path");
const semver = require("semver");
const _ = require("lodash");
class AndroidDeviceSocketsLiveSyncService extends android_device_livesync_service_base_1.AndroidDeviceLiveSyncServiceBase {
    constructor(data, $injector, platformsDataService, $staticConfig, $logger, device, $options, $cleanupService, $fs, $devicePlatformsConstants, $tempService, $filesHashService) {
        super($injector, platformsDataService, $filesHashService, $logger, device);
        this.data = data;
        this.platformsDataService = platformsDataService;
        this.$staticConfig = $staticConfig;
        this.device = device;
        this.$options = $options;
        this.$cleanupService = $cleanupService;
        this.$fs = $fs;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.$tempService = $tempService;
        this.livesyncTool = this.$injector.resolve(android_livesync_tool_1.AndroidLivesyncTool);
    }
    async beforeLiveSyncAction(deviceAppData) {
        if (!this.livesyncTool.hasConnection()) {
            try {
                const pathToLiveSyncFile = await this.$tempService.path({
                    prefix: "livesync",
                });
                this.$fs.writeFile(pathToLiveSyncFile, "");
                await this.device.fileSystem.putFile(pathToLiveSyncFile, this.getPathToLiveSyncFileOnDevice(deviceAppData.appIdentifier), deviceAppData.appIdentifier);
                await this.device.applicationManager.startApplication({
                    appId: deviceAppData.appIdentifier,
                    projectName: this.data.projectName,
                    justLaunch: true,
                    waitForDebugger: false,
                    projectDir: deviceAppData.projectDir,
                });
                await this.connectLivesyncTool(this.data.projectIdentifiers.android, deviceAppData.connectTimeout);
            }
            catch (err) {
                await this.device.fileSystem.deleteFile(this.getPathToLiveSyncFileOnDevice(deviceAppData.appIdentifier), deviceAppData.appIdentifier);
                throw err;
            }
        }
    }
    getPathToLiveSyncFileOnDevice(appIdentifier) {
        return `${constants_1.LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appIdentifier}-livesync-in-progress`;
    }
    async finalizeSync(liveSyncInfo, projectData) {
        try {
            const result = await this.doSync(liveSyncInfo, projectData);
            if (!semver.gte(this.livesyncTool.protocolVersion, AndroidDeviceSocketsLiveSyncService.MINIMAL_VERSION_LONG_LIVING_CONNECTION)) {
                this.livesyncTool.end();
            }
            return result;
        }
        catch (e) {
            this.livesyncTool.end();
            throw e;
        }
    }
    async getCleanupCommand(appIdentifier) {
        return {
            command: await this.$staticConfig.getAdbFilePath(),
            args: [
                "-s",
                this.device.deviceInfo.identifier,
                "shell",
                "rm",
                "-rf",
                appIdentifier,
            ],
        };
    }
    async doSync(liveSyncInfo, projectData) {
        const operationId = this.livesyncTool.generateOperationIdentifier();
        let result = { operationId, didRefresh: true };
        if (liveSyncInfo.modifiedFilesData.length) {
            const canExecuteFastSync = !liveSyncInfo.isFullSync &&
                this.canExecuteFastSyncForPaths(liveSyncInfo, liveSyncInfo.modifiedFilesData, projectData, this.device.deviceInfo.platform);
            const doSyncPromise = this.livesyncTool.sendDoSyncOperation({
                doRefresh: canExecuteFastSync,
                operationId,
            });
            const syncInterval = setInterval(() => {
                if (this.livesyncTool.isOperationInProgress(operationId)) {
                    this.$logger.info("Sync operation in progress...");
                }
            }, AndroidDeviceSocketsLiveSyncService.STATUS_UPDATE_INTERVAL);
            const cleanupCommand = await this.getCleanupCommand(liveSyncInfo.deviceAppData.appIdentifier);
            const actionOnEnd = async () => {
                clearInterval(syncInterval);
                await this.device.fileSystem.deleteFile(this.getPathToLiveSyncFileOnDevice(liveSyncInfo.deviceAppData.appIdentifier), liveSyncInfo.deviceAppData.appIdentifier);
                await this.$cleanupService.removeCleanupCommand(cleanupCommand);
            };
            await this.$cleanupService.addCleanupCommand(cleanupCommand);
            await doSyncPromise.then(actionOnEnd.bind(this), actionOnEnd.bind(this));
            result = await doSyncPromise;
        }
        else {
            await this.device.fileSystem.deleteFile(this.getPathToLiveSyncFileOnDevice(liveSyncInfo.deviceAppData.appIdentifier), liveSyncInfo.deviceAppData.appIdentifier);
        }
        return result;
    }
    async restartApplication(projectData, liveSyncInfo) {
        await this.device.applicationManager.restartApplication({
            appId: liveSyncInfo.deviceAppData.appIdentifier,
            projectName: projectData.projectName,
            waitForDebugger: liveSyncInfo.waitForDebugger,
            projectDir: projectData.projectDir,
        });
        if (!this.$options.justlaunch &&
            !liveSyncInfo.waitForDebugger &&
            this.livesyncTool.protocolVersion &&
            semver.gte(this.livesyncTool.protocolVersion, AndroidDeviceSocketsLiveSyncService.MINIMAL_VERSION_LONG_LIVING_CONNECTION)) {
            try {
                await this.connectLivesyncTool(liveSyncInfo.deviceAppData.appIdentifier);
            }
            catch (e) {
                this.$logger.trace("Failed to connect after app restart.");
            }
        }
    }
    async shouldRestart(projectData, liveSyncInfo) {
        let shouldRestart = false;
        const canExecuteFastSync = !liveSyncInfo.isFullSync &&
            this.canExecuteFastSyncForPaths(liveSyncInfo, liveSyncInfo.modifiedFilesData, projectData, this.device.deviceInfo.platform);
        if (!canExecuteFastSync ||
            !liveSyncInfo.didRefresh ||
            liveSyncInfo.waitForDebugger) {
            shouldRestart = true;
        }
        return shouldRestart;
    }
    async tryRefreshApplication(projectData, liveSyncInfo) {
        return true;
    }
    async removeFiles(deviceAppData, localToDevicePaths, projectFilesPath) {
        await this.livesyncTool.removeFiles(_.map(localToDevicePaths, (element) => element.filePath));
        const deviceHashService = this.device.fileSystem.getDeviceHashService(deviceAppData.appIdentifier);
        await deviceHashService.removeHashes(localToDevicePaths);
    }
    async transferFilesOnDevice(deviceAppData, localToDevicePaths) {
        const files = _.map(localToDevicePaths, (localToDevicePath) => localToDevicePath.getLocalPath());
        await this.livesyncTool.sendFiles(files);
    }
    async transferDirectoryOnDevice(deviceAppData, localToDevicePaths, projectFilesPath) {
        await this.livesyncTool.sendDirectory(projectFilesPath);
    }
    async connectLivesyncTool(appIdentifier, connectTimeout) {
        const platformData = this.platformsDataService.getPlatformData(this.$devicePlatformsConstants.Android, this.data);
        const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName);
        if (!this.livesyncTool.hasConnection()) {
            await this.livesyncTool.connect({
                appIdentifier,
                deviceIdentifier: this.device.deviceInfo.identifier,
                appPlatformsPath: projectFilesPath,
                connectTimeout,
            });
        }
    }
}
exports.AndroidDeviceSocketsLiveSyncService = AndroidDeviceSocketsLiveSyncService;
AndroidDeviceSocketsLiveSyncService.STATUS_UPDATE_INTERVAL = 10000;
AndroidDeviceSocketsLiveSyncService.MINIMAL_VERSION_LONG_LIVING_CONNECTION = "0.2.0";
