"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const utils_fs_1 = require("@ionic/utils-fs");
const Debug = require("debug");
const fs_1 = require("fs");
const path = require("path");
const errors_1 = require("../errors");
const cli_1 = require("../utils/cli");
const process_1 = require("../utils/process");
const lib_errors_1 = require("./lib/lib-errors");
const app_1 = require("./utils/app");
const device_1 = require("./utils/device");
const simulator_1 = require("./utils/simulator");
const debug = Debug('native-run:ios:run');
async function runIpaOrAppFile({ udid, devices, simulators, appPath, bundleId, waitForApp, preferSimulator, }) {
    if (udid) {
        if (devices.find((d) => d.UniqueDeviceID === udid)) {
            await (0, device_1.runOnDevice)(udid, appPath, bundleId, waitForApp);
        }
        else if (simulators.find((s) => s.udid === udid)) {
            await (0, simulator_1.runOnSimulator)(udid, appPath, bundleId, waitForApp);
        }
        else {
            throw new errors_1.IOSRunException(`No device or simulator with UDID "${udid}" found`, errors_1.ERR_TARGET_NOT_FOUND);
        }
    }
    else if (devices.length && !preferSimulator) {
        // no udid, use first connected device
        await (0, device_1.runOnDevice)(devices[0].UniqueDeviceID, appPath, bundleId, waitForApp);
    }
    else {
        // use default sim
        await (0, simulator_1.runOnSimulator)(simulators[simulators.length - 1].udid, appPath, bundleId, waitForApp);
    }
}
async function runIpaOrAppFileOnInterval(config) {
    const maxRetryCount = 12; // 1 minute
    const retryInterval = 5000; // 5 seconds
    let error;
    let retryCount = 0;
    const retry = async () => {
        process.stderr.write('Please unlock your device. Waiting 5 seconds...\n');
        retryCount++;
        await (0, process_1.wait)(retryInterval);
        await run();
    };
    const run = async () => {
        try {
            await runIpaOrAppFile(config);
        }
        catch (err) {
            if (err instanceof lib_errors_1.IOSLibError && err.code == 'DeviceLocked' && retryCount < maxRetryCount) {
                await retry();
            }
            else {
                if (retryCount >= maxRetryCount) {
                    error = new errors_1.IOSRunException(`Device still locked after 1 minute. Aborting.`, errors_1.ERR_DEVICE_LOCKED);
                }
                else {
                    error = err;
                }
            }
        }
    };
    await run();
    if (error) {
        throw error;
    }
}
async function run(args) {
    let appPath = (0, cli_1.getOptionValue)(args, '--app');
    if (!appPath) {
        throw new errors_1.CLIException('--app is required', errors_1.ERR_BAD_INPUT);
    }
    const udid = (0, cli_1.getOptionValue)(args, '--target');
    const preferSimulator = args.includes('--virtual');
    const waitForApp = args.includes('--connect');
    const isIPA = appPath.endsWith('.ipa');
    if (!(0, fs_1.existsSync)(appPath)) {
        throw new errors_1.IOSRunException(`Path '${appPath}' not found`);
    }
    try {
        if (isIPA) {
            const { tmpdir } = await Promise.resolve().then(() => require('os'));
            const tempDir = (0, fs_1.mkdtempSync)(`${tmpdir()}${path.sep}`);
            debug(`Unzipping .ipa to ${tempDir}`);
            const appDir = await (0, app_1.unzipIPA)(appPath, tempDir);
            appPath = path.join(tempDir, appDir);
        }
        const bundleId = await (0, app_1.getBundleId)(appPath);
        const [devices, simulators] = await Promise.all([(0, device_1.getConnectedDevices)(), (0, simulator_1.getSimulators)()]);
        // try to run on device or simulator with udid
        const config = {
            udid,
            devices,
            simulators,
            appPath,
            bundleId,
            waitForApp,
            preferSimulator,
        };
        await runIpaOrAppFileOnInterval(config);
    }
    finally {
        if (isIPA) {
            try {
                await (0, utils_fs_1.remove)(appPath);
            }
            catch {
                // ignore
            }
        }
    }
}
exports.run = run;
