import { execAsync } from '../../utils.js';
import { SimulatorDevice } from './SimulatorDevice.js';
import { createModuleLogger } from '../../logger.js';
const logger = createModuleLogger('Devices');
/**
 * Device discovery and management.
 * Provides methods to find and list simulator devices.
 * Future-ready for physical device support.
 */
export class Devices {
    /**
     * Find a device by name or UDID
     */
    async find(nameOrId) {
        try {
            const { stdout } = await execAsync('xcrun simctl list devices --json');
            const data = JSON.parse(stdout);
            // Collect all matching devices with their raw data for sorting
            const matchingDevices = [];
            for (const [runtime, deviceList] of Object.entries(data.devices)) {
                for (const device of deviceList) {
                    if (device.udid === nameOrId || device.name === nameOrId) {
                        matchingDevices.push({
                            device: new SimulatorDevice(device.udid, device.name, this.extractPlatformFromRuntime(runtime), runtime),
                            state: device.state,
                            isAvailable: device.isAvailable
                        });
                    }
                }
            }
            if (matchingDevices.length === 0) {
                logger.debug({ nameOrId }, 'Device not found');
                return null;
            }
            // Sort to prefer available and booted devices
            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 (fresh state from listing)
                if (a.state === 'Booted' && b.state !== 'Booted')
                    return -1;
                if (a.state !== 'Booted' && b.state === 'Booted')
                    return 1;
                return 0;
            });
            const selected = matchingDevices[0];
            // Warn if selected device is not available
            if (!selected.isAvailable) {
                logger.warn({
                    nameOrId,
                    deviceId: selected.device.id,
                    runtime: selected.device.runtime
                }, 'Selected device is not available - may fail to boot');
            }
            return selected.device;
        }
        catch (error) {
            logger.error({ error: error.message }, 'Failed to find device');
            throw new Error(`Failed to find device: ${error.message}`);
        }
    }
    /**
     * List all available simulators, optionally filtered by platform
     */
    async listSimulators(platform) {
        try {
            const { stdout } = await execAsync('xcrun simctl list devices --json');
            const data = JSON.parse(stdout);
            const devices = [];
            for (const [runtime, deviceList] of Object.entries(data.devices)) {
                const extractedPlatform = this.extractPlatformFromRuntime(runtime);
                // Filter by platform if specified
                if (platform && !this.matchesPlatform(extractedPlatform, platform)) {
                    continue;
                }
                for (const device of deviceList) {
                    if (device.isAvailable) {
                        devices.push(new SimulatorDevice(device.udid, device.name, extractedPlatform, runtime));
                    }
                }
            }
            return devices;
        }
        catch (error) {
            logger.error({ error: error.message }, 'Failed to list simulators');
            throw new Error(`Failed to list simulators: ${error.message}`);
        }
    }
    /**
     * Get the currently booted simulator, if any
     */
    async getBooted() {
        try {
            const { stdout } = await execAsync('xcrun simctl list devices --json');
            const data = JSON.parse(stdout);
            for (const [runtime, deviceList] of Object.entries(data.devices)) {
                for (const device of deviceList) {
                    if (device.state === 'Booted' && device.isAvailable) {
                        return new SimulatorDevice(device.udid, device.name, this.extractPlatformFromRuntime(runtime), runtime);
                    }
                }
            }
            logger.debug('No booted simulator found');
            return null;
        }
        catch (error) {
            logger.error({ error: error.message }, 'Failed to get booted device');
            throw new Error(`Failed to get booted device: ${error.message}`);
        }
    }
    /**
     * Find the first available device for a platform
     */
    async findFirstAvailable(platform) {
        const devices = await this.listSimulators(platform);
        // First, look for an already booted device
        const booted = devices.find((d) => d.isBooted());
        if (booted) {
            logger.debug({ device: booted.name, id: booted.id }, 'Using already booted device');
            return booted;
        }
        // Otherwise, return the first available device
        const available = devices[0];
        if (available) {
            logger.debug({ device: available.name, id: available.id }, 'Found available device');
            return available;
        }
        logger.debug({ platform }, 'No available devices for platform');
        return null;
    }
    /**
     * Extract platform from runtime string
     */
    extractPlatformFromRuntime(runtime) {
        const runtimeLower = runtime.toLowerCase();
        if (runtimeLower.includes('ios'))
            return 'iOS';
        if (runtimeLower.includes('tvos'))
            return 'tvOS';
        if (runtimeLower.includes('watchos'))
            return 'watchOS';
        if (runtimeLower.includes('xros') || runtimeLower.includes('visionos'))
            return 'visionOS';
        // Default fallback
        return 'iOS';
    }
    /**
     * Check if a runtime matches a platform
     */
    matchesPlatform(extractedPlatform, targetPlatform) {
        const extractedLower = extractedPlatform.toLowerCase();
        const targetLower = targetPlatform.toLowerCase();
        // Handle visionOS special case (internally called xrOS)
        if (targetLower === 'visionos') {
            return extractedLower === 'visionos' || extractedLower === 'xros';
        }
        return extractedLower === targetLower;
    }
    /**
     * Find an available device for a specific platform
     * Returns the first available device, preferring already booted ones
     */
    async findForPlatform(platform) {
        logger.debug({ platform }, 'Finding device for platform');
        try {
            const devices = await this.listSimulators();
            // Filter devices for the requested platform
            const platformDevices = devices.filter((device) => this.matchesPlatform(this.extractPlatformFromRuntime(device.runtime), platform));
            if (platformDevices.length === 0) {
                logger.warn({ platform }, 'No devices found for platform');
                return null;
            }
            // Try to find a booted device first
            const booted = await this.getBooted();
            if (booted && platformDevices.some(d => d.id === booted.id)) {
                logger.debug({
                    device: booted.name,
                    id: booted.id
                }, 'Selected already booted device for platform');
                return booted;
            }
            // Otherwise just return the first available device
            const selected = platformDevices[0];
            logger.debug({
                device: selected.name,
                id: selected.id
            }, 'Selected device for platform');
            return selected;
        }
        catch (error) {
            logger.error({ error: error.message, platform }, 'Failed to find device for platform');
            throw new Error(`Failed to find device for platform ${platform}: ${error.message}`);
        }
    }
    /**
     * Future: List physical devices connected to the system
     * Currently returns empty array as physical device support is not yet implemented
     */
    async listPhysical() {
        // Future implementation for physical devices
        // Would use xcrun devicectl or ios-deploy
        return [];
    }
}
// Export a default instance for convenience
export const devices = new Devices();
//# sourceMappingURL=Devices.js.map