"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.listSimulators = listSimulators;
exports.parseOSVersion = parseOSVersion;
exports.listRealDevices = listRealDevices;
exports.getXcodeInstallStatus = getXcodeInstallStatus;
exports.runSimulator = runSimulator;
exports.shutdownSimulator = shutdownSimulator;
exports.isXcRunInstalled = isXcRunInstalled;
exports.getXcodeVersion = getXcodeVersion;
exports.getFfmpegVersion = getFfmpegVersion;
exports.getPlistFileForApp = getPlistFileForApp;
exports.getIOSAppFileInfo = getIOSAppFileInfo;
const shellUtil_1 = require("./shellUtil");
const path = __importStar(require("path"));
const adm_zip_1 = __importDefault(require("adm-zip"));
const promises_1 = require("fs/promises");
const parse_1 = require("@plist/parse");
async function listSimulators() {
    const availableSimulators = await (0, shellUtil_1.asyncSpawn)('xcrun', [
        'simctl',
        'list',
        'devices',
        '--json',
        'available',
    ]);
    const formatted = {};
    const parsed = JSON.parse(availableSimulators.join(''));
    Object.entries(parsed.devices).forEach(([runtime, devices]) => {
        const parsedOSVersion = parseOSVersion(runtime);
        devices.forEach((device) => {
            device.osVersion = parsedOSVersion;
            formatted[device.udid] = { ...device };
        });
    });
    return formatted;
}
function parseOSVersion(runtime) {
    if (!runtime) {
        return undefined;
    }
    const match = /.*Runtime\.(?<os>\w+)-(?<version>.+)/.exec(runtime);
    if (!match?.groups) {
        return undefined;
    }
    return `${match.groups.os} ${match.groups.version.replace('-', '.')}`;
}
async function listRealDevices() {
    const availableDevicesResponse = await (0, shellUtil_1.asyncSpawn)('xcrun', [
        'xctrace',
        'list',
        'devices',
    ]);
    const formattedResults = {};
    let trackingHeader = '';
    availableDevicesResponse.forEach((deviceInfo) => {
        if (deviceInfo.startsWith('==')) {
            const header = deviceInfo
                .replace(/==/g, '')
                .replace(/\s/g, '')
                .toLowerCase();
            formattedResults[header] = {};
            trackingHeader = header;
        }
        else if (deviceInfo.length) {
            const matches = deviceInfo.matchAll(/(.*) \((.*)\)/gm);
            const matched = [];
            for (const match of matches) {
                matched.push(match);
            }
            const name = `${matched[0][1]}`;
            const udid = `${matched[0][2]}`;
            formattedResults[trackingHeader][udid] = {
                name,
                udid,
            };
        }
    });
    return formattedResults.devices ?? {};
}
async function getXcodeInstallStatus() {
    const xcodeInstallStatus = {
        installed: false,
        cliToolsInstalled: false,
    };
    const xCodeVersion = await getXcodeVersion();
    if (xCodeVersion) {
        xcodeInstallStatus.installed = true;
        xcodeInstallStatus.version = xCodeVersion;
        xcodeInstallStatus.cliToolsInstalled = isXcRunInstalled();
    }
    return xcodeInstallStatus;
}
async function runSimulator(udid, headless = false) {
    if (!headless) {
        openSimulatorApp(udid);
    }
    else {
        await (0, shellUtil_1.asyncSpawn)('xcrun', ['simctl', 'boot', udid]);
    }
    await (0, shellUtil_1.asyncSpawn)('xcrun', ['simctl', 'bootstatus', udid]);
    return;
}
async function shutdownSimulator(udid) {
    await (0, shellUtil_1.asyncSpawn)('xcrun', ['simctl', 'shutdown', udid]);
}
function isXcRunInstalled() {
    (0, shellUtil_1.syncExec)('xcrun', ['--version']);
    return true;
}
async function getXcodeVersion() {
    const xcodeVersionResponse = await (0, shellUtil_1.asyncSpawn)('xcodebuild', ['-version']);
    return xcodeVersionResponse[0].match(/^Xcode (.*)/)?.[1];
}
function getFfmpegVersion() {
    const ffmpegVersionResponse = (0, shellUtil_1.syncExec)('ffmpeg', ['-version']);
    return ffmpegVersionResponse[0].match(/^ffmpeg version (.*) Copyright/)?.[1];
}
function openSimulatorApp(udid) {
    const udidArg = udid ? ` --args -CurrentDeviceUDID ${udid}` : '';
    (0, shellUtil_1.syncExec)('open', ['-a', `Simulator${udidArg}`]);
}
async function getPlistFileForApp(appPath) {
    const isDirectory = (await (0, promises_1.stat)(appPath)).isDirectory();
    if (isDirectory) {
        return getPlistFileFromPath(appPath);
    }
    return getPlistFileFromArchive(appPath);
}
async function getPlistFileFromPath(appPath) {
    const fileBuffer = await (0, promises_1.readFile)(path.resolve(appPath, 'Info.plist'));
    const arrayBuffer = new Uint8Array(fileBuffer).buffer;
    return (0, parse_1.parse)(arrayBuffer);
}
async function getPlistFileFromArchive(appArchivePath) {
    const appArchive = new adm_zip_1.default(appArchivePath);
    const appDirectoryPath = appArchive
        .getEntries()
        .find((entry) => path.dirname(entry.entryName).endsWith('.app'));
    if (!appDirectoryPath) {
        throw new Error(`No .app directory found in archive ${appArchivePath}`);
    }
    const plistPath = path.join(path.dirname(appDirectoryPath.entryName), 'Info.plist');
    const plist = await new Promise((resolve, reject) => appArchive.readFileAsync(plistPath, (data, err) => {
        if (err) {
            reject(err);
        }
        else {
            resolve(data);
        }
    }));
    if (!plist) {
        throw new Error(`No Info.plist found in app archive ${appArchivePath}`);
    }
    return (0, parse_1.parse)(new Uint8Array(plist).buffer);
}
async function getIOSAppFileInfo(appPath) {
    const parsedPlist = await getPlistFileForApp(appPath);
    if (Array.isArray(parsedPlist)) {
        return getIOSAppFileInfoFromPlistDictionary(parsedPlist[0]);
    }
    return getIOSAppFileInfoFromPlistDictionary(parsedPlist);
}
function getIOSAppFileInfoFromPlistDictionary(plist) {
    return {
        identifier: plist.CFBundleIdentifier,
        name: plist.CFBundleName,
        packageType: plist.CFBundlePackageType,
        version: plist.CFBundleShortVersionString,
        supportedPlatforms: plist.CFBundleSupportedPlatforms,
        platformName: plist.DTPlatformName,
        platformVersion: plist.DTPlatformVersion,
        minVersionSupported: plist.MinimumOSVersion,
        buildMachineOSInfo: plist.BuildMachineOSBuild,
    };
}
