import { execAsync } from '../../utils.js';
import { createModuleLogger } from '../../logger.js';
const logger = createModuleLogger('SimulatorBoot');
/**
 * Simple utility to boot simulators for Xcode builds
 * Extracted shared logic from BuildXcodeTool and RunXcodeTool
 */
export class SimulatorBoot {
    /**
     * Boot a simulator
     */
    async boot(deviceId) {
        try {
            await execAsync(`xcrun simctl boot "${deviceId}"`);
            logger.debug({ deviceId }, 'Simulator booted successfully');
        }
        catch (error) {
            // Check if already booted
            if (!error.message?.includes('Unable to boot device in current state: Booted')) {
                logger.error({ error: error.message, deviceId }, 'Failed to boot simulator');
                throw new Error(`Failed to boot simulator: ${error.message}`);
            }
            logger.debug({ deviceId }, 'Simulator already booted');
        }
    }
    /**
     * Shutdown a simulator
     */
    async shutdown(deviceId) {
        try {
            await execAsync(`xcrun simctl shutdown "${deviceId}"`);
            logger.debug({ deviceId }, 'Simulator shutdown successfully');
        }
        catch (error) {
            logger.error({ error: error.message, deviceId }, 'Failed to shutdown simulator');
            throw new Error(`Failed to shutdown simulator: ${error.message}`);
        }
    }
    /**
     * Opens the Simulator app GUI (skipped during tests)
     */
    async openSimulatorApp() {
        // Skip opening GUI during tests
        if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID) {
            logger.debug('Skipping Simulator GUI in test environment');
            return;
        }
        try {
            await execAsync('open -g -a Simulator');
            logger.debug('Opened Simulator app');
        }
        catch (error) {
            logger.warn({ error: error.message }, 'Failed to open Simulator app');
        }
    }
    /**
     * Ensures a simulator is booted for the given platform and device
     * Returns the booted device ID (UDID)
     */
    async ensureBooted(platform, deviceId) {
        if (!deviceId) {
            // No specific device requested, use first available
            return this.bootFirstAvailable(platform);
        }
        // Check if the device exists and get its state
        try {
            const { stdout } = await execAsync('xcrun simctl list devices --json');
            const data = JSON.parse(stdout);
            // Collect all matching devices first, then pick the best one
            const matchingDevices = [];
            for (const deviceList of Object.values(data.devices)) {
                for (const device of deviceList) {
                    if (device.udid === deviceId || device.name === deviceId) {
                        matchingDevices.push(device);
                    }
                }
            }
            if (matchingDevices.length === 0) {
                throw new Error(`Device '${deviceId}' not found`);
            }
            // Sort devices: prefer available ones, then already booted ones
            matchingDevices.sort((a, b) => {
                // First priority: available devices
                if (a.isAvailable && !b.isAvailable)
                    return -1;
                if (!a.isAvailable && b.isAvailable)
                    return 1;
                // Second priority: booted devices
                if (a.state === 'Booted' && b.state !== 'Booted')
                    return -1;
                if (a.state !== 'Booted' && b.state === 'Booted')
                    return 1;
                return 0;
            });
            // Use the best matching device
            const device = matchingDevices[0];
            if (!device.isAvailable) {
                // All matching devices are unavailable
                const availableErrors = matchingDevices
                    .map(d => `${d.name} (${d.udid}): ${d.availabilityError || 'unavailable'}`)
                    .join(', ');
                throw new Error(`All devices named '${deviceId}' are unavailable: ${availableErrors}`);
            }
            if (device.state === 'Booted') {
                logger.debug({ deviceId: device.udid, name: device.name }, 'Device already booted');
                // Still open the Simulator app to make it visible
                await this.openSimulatorApp();
                return device.udid;
            }
            // Boot the device
            logger.info({ deviceId: device.udid, name: device.name }, 'Booting simulator');
            try {
                await execAsync(`xcrun simctl boot "${device.udid}"`);
            }
            catch (error) {
                // Device might already be booted
                if (!error.message?.includes('Unable to boot device in current state: Booted')) {
                    throw error;
                }
            }
            // Open the Simulator app to show the GUI
            await this.openSimulatorApp();
            return device.udid;
        }
        catch (error) {
            logger.error({ error: error.message, deviceId }, 'Failed to boot simulator');
            throw new Error(`Failed to boot simulator: ${error.message}`);
        }
    }
    /**
     * Boots the first available simulator for a platform
     */
    async bootFirstAvailable(platform) {
        try {
            const { stdout } = await execAsync('xcrun simctl list devices --json');
            const data = JSON.parse(stdout);
            // Find first available device for the platform
            for (const [runtime, deviceList] of Object.entries(data.devices)) {
                const runtimeLower = runtime.toLowerCase();
                const platformLower = platform.toLowerCase();
                // Handle visionOS which is internally called xrOS
                const isVisionOS = platformLower === 'visionos' && runtimeLower.includes('xros');
                const isOtherPlatform = platformLower !== 'visionos' && runtimeLower.includes(platformLower);
                if (!isVisionOS && !isOtherPlatform) {
                    continue;
                }
                for (const device of deviceList) {
                    if (!device.isAvailable)
                        continue;
                    // Check if already booted
                    if (device.state === 'Booted') {
                        logger.debug({ deviceId: device.udid, name: device.name }, 'Using already booted device');
                        // Still open the Simulator app to make it visible
                        await this.openSimulatorApp();
                        return device.udid;
                    }
                    // Boot this device
                    logger.info({ deviceId: device.udid, name: device.name }, 'Booting first available simulator');
                    try {
                        await execAsync(`xcrun simctl boot ${device.udid}`);
                    }
                    catch (error) {
                        // Device might already be booted
                        if (!error.message?.includes('Unable to boot device in current state: Booted')) {
                            throw error;
                        }
                    }
                    // Open the Simulator app to show the GUI
                    await this.openSimulatorApp();
                    return device.udid;
                }
            }
            throw new Error(`No available simulators found for platform ${platform}`);
        }
        catch (error) {
            logger.error({ error: error.message, platform }, 'Failed to boot simulator');
            throw new Error(`Failed to boot simulator: ${error.message}`);
        }
    }
}
//# sourceMappingURL=SimulatorBoot.js.map