import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

/**
 * Permission status for E2E tests requiring real automation.
 */
export interface E2EPermissionStatus {
  accessibility: boolean;
  screenRecording: boolean;
  platform: NodeJS.Platform;
  isCI: boolean;
  isHeadless: boolean;
  canRunRealAutomation: boolean;
}

/**
 * Result of permission check with actionable information.
 */
export interface PermissionCheckResult {
  canProceed: boolean;
  shouldSkip: boolean;
  skipReason?: string;
  status: E2EPermissionStatus;
  warnings: string[];
}

/**
 * PermissionGuard for E2E tests.
 *
 * Checks macOS Accessibility and Screen Recording permissions
 * required for real native automation. Provides graceful skip
 * logic for CI environments or when permissions are unavailable.
 */
export class PermissionGuard {
  private cachedStatus: E2EPermissionStatus | null = null;

  /**
   * Check all permissions and determine if real automation tests can run.
   * 
   * @returns PermissionCheckResult with status and skip reason if applicable
   */
  async checkPermissions(): Promise<PermissionCheckResult> {
    const status = await this.getPermissionStatus();
    const warnings: string[] = [];

    // CI environments should always skip real automation tests
    if (status.isCI) {
      return {
        canProceed: false,
        shouldSkip: true,
        skipReason: 'Running in CI environment - real automation tests require a display',
        status,
        warnings: ['CI environment detected, skipping real automation tests'],
      };
    }

    // Headless environments cannot run real automation
    if (status.isHeadless) {
      return {
        canProceed: false,
        shouldSkip: true,
        skipReason: 'Running in headless environment - real automation tests require a display',
        status,
        warnings: ['Headless environment detected, skipping real automation tests'],
      };
    }

    // macOS-specific permission checks
    if (status.platform === 'darwin') {
      if (!status.accessibility) {
        warnings.push('macOS Accessibility permission not granted');
        warnings.push('To grant: System Preferences > Security & Privacy > Privacy > Accessibility');
      }
      if (!status.screenRecording) {
        warnings.push('macOS Screen Recording permission not granted');
        warnings.push('To grant: System Preferences > Security & Privacy > Privacy > Screen Recording');
      }

      if (!status.accessibility || !status.screenRecording) {
        return {
          canProceed: false,
          shouldSkip: true,
          skipReason: `Missing macOS permissions: ${[
            !status.accessibility && 'Accessibility',
            !status.screenRecording && 'Screen Recording',
          ].filter(Boolean).join(', ')}`,
          status,
          warnings,
        };
      }
    }

    // All checks passed
    return {
      canProceed: true,
      shouldSkip: false,
      status,
      warnings,
    };
  }

  /**
   * Get the current permission status.
   */
  async getPermissionStatus(): Promise<E2EPermissionStatus> {
    if (this.cachedStatus) {
      return this.cachedStatus;
    }

    const platform = process.platform;
    const isCI = this.detectCI();
    const isHeadless = await this.detectHeadless();

    let accessibility = true;
    let screenRecording = true;

    if (platform === 'darwin') {
      accessibility = await this.checkMacOSAccessibility();
      screenRecording = await this.checkMacOSScreenRecording();
    }

    const canRunRealAutomation = 
      !isCI && 
      !isHeadless && 
      accessibility && 
      screenRecording;

    this.cachedStatus = {
      accessibility,
      screenRecording,
      platform,
      isCI,
      isHeadless,
      canRunRealAutomation,
    };

    return this.cachedStatus;
  }

  /**
   * Detect if running in a CI environment.
   */
  private detectCI(): boolean {
    return !!(
      process.env.CI ||
      process.env.CONTINUOUS_INTEGRATION ||
      process.env.GITHUB_ACTIONS ||
      process.env.GITLAB_CI ||
      process.env.CIRCLECI ||
      process.env.TRAVIS ||
      process.env.JENKINS_URL ||
      process.env.BUILDKITE ||
      process.env.TF_BUILD // Azure DevOps
    );
  }

  /**
   * Detect if running in a headless environment (no display).
   */
  private async detectHeadless(): Promise<boolean> {
    // Check for explicit headless environment variable
    if (process.env.HEADLESS === 'true' || process.env.DISPLAY === '') {
      return true;
    }

    // On Linux, check if DISPLAY is set
    if (process.platform === 'linux' && !process.env.DISPLAY) {
      return true;
    }

    // On macOS, check if we're in a non-GUI session
    if (process.platform === 'darwin') {
      try {
        // Check if we can access the WindowServer
        const { stdout } = await execAsync('pgrep -x WindowServer');
        return !stdout.trim();
      } catch {
        // pgrep returns non-zero if no process found
        return true;
      }
    }

    return false;
  }

  /**
   * Check macOS Accessibility permission without Electron.
   * Uses AppleScript to test if we can control system events.
   */
  private async checkMacOSAccessibility(): Promise<boolean> {
    try {
      // Try to use AppleScript to check accessibility
      // This will fail if accessibility permission is not granted
      await execAsync(`osascript -e 'tell application "System Events" to return name of first process'`);
      return true;
    } catch {
      // Permission denied or System Events not accessible
      return false;
    }
  }

  /**
   * Check macOS Screen Recording permission without Electron.
   * Uses `screencapture` heuristics to detect denial.
   */
  private async checkMacOSScreenRecording(): Promise<boolean> {
    try {
      const { stderr } = await execAsync('screencapture -x -c 2>&1 || true');

      if (stderr.includes('permission') || stderr.includes('denied')) {
        return false;
      }

      return true;
    } catch {
      return false;
    }
  }

  /**
   * Clear cached permission status.
   */
  clearCache(): void {
    this.cachedStatus = null;
  }

  /**
   * Format permission status for logging.
   */
  formatStatus(status: E2EPermissionStatus): string {
    const lines = [
      `Platform: ${status.platform}`,
      `CI Environment: ${status.isCI ? 'Yes' : 'No'}`,
      `Headless: ${status.isHeadless ? 'Yes' : 'No'}`,
      `Accessibility Permission: ${status.accessibility ? '✓' : '✗'}`,
      `Screen Recording Permission: ${status.screenRecording ? '✓' : '✗'}`,
      `Can Run Real Automation: ${status.canRunRealAutomation ? '✓' : '✗'}`,
    ];
    return lines.join('\n');
  }
}

/**
 * Singleton instance for use in tests.
 */
export const permissionGuard = new PermissionGuard();

/**
 * Skip helper for Cucumber tests.
 * Call in Before hook to skip tests if permissions are unavailable.
 * 
 * @returns Skip reason if tests should be skipped, undefined otherwise
 */
export async function shouldSkipRealAutomationTests(): Promise<string | undefined> {
  const result = await permissionGuard.checkPermissions();
  
  if (result.shouldSkip) {
    console.warn('\n⚠️  Skipping real automation tests:');
    console.warn(`   ${result.skipReason}`);
    if (result.warnings.length > 0) {
      result.warnings.forEach(w => console.warn(`   - ${w}`));
    }
    return result.skipReason;
  }
  
  return undefined;
}

/**
 * Assert that real automation can proceed.
 * Throws an error with detailed information if not.
 */
export async function assertCanRunRealAutomation(): Promise<void> {
  const result = await permissionGuard.checkPermissions();
  
  if (!result.canProceed) {
    const status = permissionGuard.formatStatus(result.status);
    throw new Error(
      `Cannot run real automation tests:\n${result.skipReason}\n\nPermission Status:\n${status}`
    );
  }
}