import { z } from 'zod';
import { Platform } from '../../types.js';
import { createModuleLogger } from '../../logger.js';
import { safePathSchema, platformSchema, configurationSchema } from '../validators.js';
import { execAsync } from '../../utils.js';
import { existsSync } from 'fs';
import path from 'path';
import { SimulatorManager } from '../../simulatorManager.js';
import { PlatformHandler } from '../../platformHandler.js';
const logger = createModuleLogger('XcodeProjectBuilder');
export const buildXcodeProjectSchema = z.object({
    projectPath: safePathSchema,
    scheme: z.string().optional(),
    platform: platformSchema.optional().default(Platform.iOS),
    deviceId: z.string().optional(),
    configuration: configurationSchema
});
export class XcodeProjectBuilder {
    /**
     * Validates that a scheme supports the requested platform
     * @throws Error if the platform is not supported
     */
    async validatePlatformSupport(projectPath, scheme, platform) {
        const isWorkspace = projectPath.endsWith('.xcworkspace');
        const projectFlag = isWorkspace ? '-workspace' : '-project';
        let command = `xcodebuild -showBuildSettings ${projectFlag} "${projectPath}"`;
        if (scheme) {
            command += ` -scheme "${scheme}"`;
        }
        // Use a generic destination to check platform support
        const destination = PlatformHandler.getGenericDestination(platform);
        command += ` -destination '${destination}'`;
        try {
            logger.debug({ command }, 'Validating platform support');
            // Just check if the command succeeds - we don't need the output
            await execAsync(command, {
                maxBuffer: 1024 * 1024, // 1MB is enough for validation
                timeout: 10000 // 10 second timeout for validation
            });
            logger.debug({ platform, scheme }, 'Platform validation succeeded');
        }
        catch (error) {
            const stderr = error.stderr || '';
            const stdout = error.stdout || '';
            // Check if error indicates platform mismatch
            if (stderr.includes('Available destinations for') || stdout.includes('Available destinations for')) {
                // Extract available platforms from the error message
                const availablePlatforms = this.extractAvailablePlatforms(stderr + stdout);
                throw new Error(`Platform '${platform}' is not supported by scheme '${scheme || 'default'}'. ` +
                    `Available platforms: ${availablePlatforms.join(', ')}`);
            }
            // Some other error - let it pass through for now
            logger.warn({ error: error.message }, 'Platform validation check failed, continuing anyway');
        }
    }
    /**
     * Extracts available platforms from xcodebuild error output
     */
    extractAvailablePlatforms(output) {
        const platforms = new Set();
        const lines = output.split('\n');
        for (const line of lines) {
            // Look for lines like "{ platform:watchOS" or "{ platform:iOS Simulator"
            const match = line.match(/\{ platform:([^,}]+)/);
            if (match) {
                let platform = match[1].trim();
                // Normalize platform names
                if (platform.includes('Simulator')) {
                    platform = platform.replace(' Simulator', '');
                }
                platforms.add(platform);
            }
        }
        return Array.from(platforms);
    }
    async execute(args) {
        const validated = buildXcodeProjectSchema.parse(args);
        const { projectPath, scheme, platform, deviceId, configuration } = validated;
        logger.info({ projectPath, scheme, platform, configuration }, 'Building Xcode project');
        try {
            // Check if project exists
            if (!existsSync(projectPath)) {
                throw new Error(`Project path does not exist: ${projectPath}`);
            }
            // Validate that the scheme supports the requested platform
            await this.validatePlatformSupport(projectPath, scheme, platform);
            // Determine destination based on whether deviceId was specified
            let destination;
            if (deviceId) {
                // Specific device requested - boot it and build for it (caches build for running)
                let bootedDevice = '';
                if (PlatformHandler.needsSimulator(platform)) {
                    bootedDevice = await SimulatorManager.ensureSimulatorBooted(platform, deviceId);
                }
                destination = PlatformHandler.getDestination(platform, bootedDevice || deviceId);
            }
            else {
                // No device specified - use generic destination for fast compilation check
                destination = PlatformHandler.getGenericDestination(platform);
            }
            // Build command using xcodebuild
            const isWorkspace = projectPath.endsWith('.xcworkspace');
            const projectFlag = isWorkspace ? '-workspace' : '-project';
            let command = `xcodebuild ${projectFlag} "${projectPath}"`;
            // Add scheme if provided
            if (scheme) {
                command += ` -scheme "${scheme}"`;
            }
            // Add configuration
            command += ` -configuration "${configuration}"`;
            // Add destination
            command += ` -destination '${destination}'`;
            // Add derived data path
            command += ' -derivedDataPath ./DerivedData';
            // Add build action
            command += ' build';
            logger.debug({ command }, 'Build command');
            await execAsync(command, {
                maxBuffer: 10 * 1024 * 1024 // 10MB buffer
            });
            // Try to find the built app
            let appPath = null;
            try {
                const { stdout: findOutput } = await execAsync('find "./DerivedData" -name "*.app" -type d | head -1');
                appPath = findOutput.trim() || null;
            }
            catch {
                // Ignore errors finding app path
            }
            // Check if the configuration actually worked by looking at the build path
            // If the app is in a folder named after the configuration, it worked
            let actualConfiguration = configuration;
            let configNote = '';
            if (appPath && !appPath.toLowerCase().includes(configuration.toLowerCase())) {
                // The app wasn't built in the expected configuration directory
                // This means Xcode fell back to Release
                actualConfiguration = 'Release';
                configNote = ` - ${configuration} configuration was not found`;
            }
            return {
                content: [
                    {
                        type: 'text',
                        text: `Build succeeded: ${scheme || path.basename(projectPath)}
Platform: ${platform}
Configuration: ${actualConfiguration}${configNote}
App path: ${appPath || 'N/A'}`
                    }
                ]
            };
        }
        catch (error) {
            logger.error({ error, projectPath, scheme, platform }, 'Build failed');
            // Combine stdout and stderr to get full output
            const stdout = error.stdout || '';
            const stderr = error.stderr || '';
            const errorMessage = error.message || 'Unknown build error';
            // Prefer stderr if it has the actual error details, otherwise use stdout
            let responseText;
            if (stderr && stderr.includes('xcodebuild: error')) {
                // stderr has the actual error - use it
                responseText = stderr;
            }
            else if (stdout && stdout.includes('xcodebuild')) {
                // stdout has build output
                responseText = stdout;
            }
            else if (stderr) {
                // Use any stderr we have
                responseText = stderr;
            }
            else {
                // Fallback to error message
                responseText = `Build failed: ${errorMessage}`;
            }
            return {
                content: [
                    {
                        type: 'text',
                        text: responseText
                    }
                ]
            };
        }
    }
}
//# sourceMappingURL=XcodeProjectBuilder.js.map