import { execAsync } from './shell-utils';
import { spawn } from 'child_process';
import log from 'electron-log';

/**
 * Escape single quotes in AppleScript strings
 * Converts ' to '\''
 */
export function escapeAppleScript(script: string): string {
  return script.replace(/'/g, "'\\''");
}

/**
 * Execute an AppleScript command
 * @param script - The AppleScript code to execute
 * @returns Promise with stdout and stderr
 */
export async function executeAppleScript(script: string): Promise<{ stdout: string; stderr: string }> {
  const escapedScript = escapeAppleScript(script);
  log.debug('Executing AppleScript:', script.substring(0, 100) + '...');

  try {
    const result = await execAsync(`osascript -e '${escapedScript}'`);
    return result;
  } catch (error: any) {
    log.error('AppleScript execution failed:', error.message);
    throw error;
  }
}

/**
 * Execute an AppleScript command with administrator privileges
 * Uses 'do shell script ... with administrator privileges' pattern
 * @param shellCommand - The shell command to execute with sudo
 * @param prompt - Optional custom prompt text for the admin dialog
 * @returns Promise with stdout and stderr
 */
export async function executeAppleScriptWithAdmin(
  shellCommand: string,
  prompt?: string
): Promise<{ stdout: string; stderr: string }> {
  const promptText = prompt || 'This operation requires administrator privileges:';

  // Escape the shell command for use in AppleScript
  const escapedCommand = shellCommand.replace(/\\/g, '\\\\').replace(/"/g, '\\"');

  const script = `do shell script "${escapedCommand}" with administrator privileges with prompt "${promptText}"`;

  log.debug('Executing AppleScript with admin privileges');

  try {
    const result = await executeAppleScript(script);
    return result;
  } catch (error: any) {
    log.error('AppleScript admin execution failed:', error.message);
    throw error;
  }
}

/**
 * Execute a multi-line AppleScript using spawn for better streaming/output control
 * Useful for long-running scripts or when you need to capture output in real-time
 * @param script - The AppleScript code to execute
 * @param onOutput - Optional callback for real-time output
 * @returns Promise that resolves when the script completes
 */
export function executeAppleScriptStream(
  script: string,
  onOutput?: (output: string) => void
): Promise<{ success: boolean; output: string; error?: string }> {
  return new Promise((resolve) => {
    let output = '';
    let errorOutput = '';

    const childProcess = spawn('osascript', ['-e', script], {
      env: process.env
    });

    childProcess.stdout.on('data', (data: Buffer) => {
      const text = data.toString();
      output += text;
      if (onOutput) {
        onOutput(text);
      }
    });

    childProcess.stderr.on('data', (data: Buffer) => {
      const text = data.toString();
      errorOutput += text;
      log.warn('AppleScript stderr:', text);
    });

    childProcess.on('close', (code: number | null) => {
      if (code === 0) {
        log.debug('AppleScript completed successfully');
        resolve({ success: true, output });
      } else {
        log.error('AppleScript failed with code:', code);
        resolve({ success: false, output, error: errorOutput });
      }
    });

    childProcess.on('error', (error: Error) => {
      log.error('AppleScript process error:', error);
      resolve({ success: false, output, error: error.message });
    });
  });
}

/**
 * Show a dialog with AppleScript and get user input
 * @param message - The message to display
 * @param defaultAnswer - Optional default answer
 * @param hiddenAnswer - Whether to hide the answer (for passwords)
 * @returns The user's input or null if cancelled
 */
export async function showAppleScriptDialog(
  message: string,
  defaultAnswer: string = '',
  hiddenAnswer: boolean = false
): Promise<string | null> {
  const hiddenFlag = hiddenAnswer ? 'with hidden answer' : '';
  const script = `display dialog "${escapeAppleScript(message)}" default answer "${escapeAppleScript(defaultAnswer)}" ${hiddenFlag}`;

  try {
    const result = await executeAppleScript(script);
    // Extract the text returned from the dialog
    const match = result.stdout.match(/text returned:(.+)/);
    return match ? match[1].trim() : null;
  } catch (error) {
    // User cancelled or error occurred
    return null;
  }
}

/**
 * Launch an application using AppleScript
 * @param appName - The name of the application (e.g., "Docker")
 * @returns Promise that resolves when the app is launched
 */
export async function launchApplication(appName: string): Promise<void> {
  const script = `tell application "${escapeAppleScript(appName)}" to activate`;
  log.info(`Launching application via AppleScript: ${appName}`);

  try {
    await executeAppleScript(script);
    log.info(`Successfully launched ${appName}`);
  } catch (error: any) {
    log.error(`Failed to launch ${appName}:`, error.message);
    throw error;
  }
}

/**
 * Check if an application is running using AppleScript
 * @param appName - The name of the application
 * @returns true if the application is running
 */
export async function isApplicationRunning(appName: string): Promise<boolean> {
  const script = `tell application "System Events" to (name of processes) contains "${escapeAppleScript(appName)}"`;

  try {
    const result = await executeAppleScript(script);
    return result.stdout.trim() === 'true';
  } catch (error) {
    log.warn(`Error checking if ${appName} is running:`, error);
    return false;
  }
}
