import { getWindows, getActiveWindow, focusWindow, Window } from '@nut-tree-fork/nut-js';
import type { ScreenRegion } from '../../../domain/value-objects/ScreenRegion';
import type { WindowInfo, WindowFocusResult } from '../../../application/ports/IScreenAutomation';
import type { ILogger } from '../../../application/ports/ILogger';
import { NoOpLogAdapter } from '../logging/NoOpLogAdapter';

/**
 * Service for managing browser window focus and enumeration.
 * Uses nut.js window management APIs to find and focus browser windows.
 */
export class WindowFocusService {
  private logger: ILogger;
  private defaultTitlePattern: string;

  constructor(defaultTitlePattern?: string, logger?: ILogger) {
    this.logger = logger ?? new NoOpLogAdapter();
    this.defaultTitlePattern = defaultTitlePattern ?? 'iRacing';
  }

  /**
   * Find and focus a browser window matching the title pattern.
   * @param titlePattern - Pattern to match in window title (default: 'iRacing')
   * @returns WindowFocusResult with window info if successful
   */
  async focusBrowserWindow(titlePattern?: string): Promise<WindowFocusResult> {
    const pattern = titlePattern ?? this.defaultTitlePattern;
    
    try {
      this.logger.debug('Searching for browser window', { titlePattern: pattern });
      
      const windows = await getWindows();
      
      for (const windowHandle of windows) {
        try {
          const windowRef = new Window(windowHandle);
          const title = await windowRef.getTitle();
          
          if (title.toLowerCase().includes(pattern.toLowerCase())) {
            this.logger.debug('Found matching window', { title, handle: windowHandle });
            
            await focusWindow(windowRef);
            
            // Get window bounds after focusing
            const region = await windowRef.getRegion();
            const bounds: ScreenRegion = {
              x: region.left,
              y: region.top,
              width: region.width,
              height: region.height,
            };
            
            const windowInfo: WindowInfo = {
              title,
              bounds,
              handle: windowHandle,
              isActive: true,
            };
            
            this.logger.info('Browser window focused', { title, bounds });
            
            return {
              success: true,
              window: windowInfo,
            };
          }
        } catch (windowError) {
          // Skip windows that can't be accessed
          this.logger.debug('Could not access window', { handle: windowHandle, error: String(windowError) });
          continue;
        }
      }
      
      this.logger.warn('No matching browser window found', { titlePattern: pattern });
      
      return {
        success: false,
        error: `No window found matching pattern: ${pattern}`,
      };
    } catch (error) {
      const errorMsg = `Window focus failed: ${error}`;
      this.logger.error('Window focus failed', error instanceof Error ? error : new Error(errorMsg));
      
      return {
        success: false,
        error: errorMsg,
      };
    }
  }

  /**
   * Get the currently active window.
   * @returns WindowInfo for the active window, or null if unable to determine
   */
  async getActiveWindow(): Promise<WindowInfo | null> {
    try {
      const activeWindow = await getActiveWindow();
      const title = await activeWindow.getTitle();
      const region = await activeWindow.getRegion();
      
      const bounds: ScreenRegion = {
        x: region.left,
        y: region.top,
        width: region.width,
        height: region.height,
      };
      
      return {
        title,
        bounds,
        handle: 0, // Active window doesn't expose handle directly
        isActive: true,
      };
    } catch (error) {
      this.logger.error('Failed to get active window', error instanceof Error ? error : new Error(String(error)));
      return null;
    }
  }

  /**
   * List all visible windows.
   * @returns Array of WindowInfo for all accessible windows
   */
  async listWindows(): Promise<WindowInfo[]> {
    const result: WindowInfo[] = [];
    
    try {
      const windows = await getWindows();
      const activeWindow = await getActiveWindow();
      const activeTitle = await activeWindow.getTitle();
      
      for (const windowHandle of windows) {
        try {
          const windowRef = new Window(windowHandle);
          const title = await windowRef.getTitle();
          const region = await windowRef.getRegion();
          
          const bounds: ScreenRegion = {
            x: region.left,
            y: region.top,
            width: region.width,
            height: region.height,
          };
          
          result.push({
            title,
            bounds,
            handle: windowHandle,
            isActive: title === activeTitle,
          });
        } catch {
          // Skip inaccessible windows
          continue;
        }
      }
    } catch (error) {
      this.logger.error('Failed to list windows', error instanceof Error ? error : new Error(String(error)));
    }
    
    return result;
  }

  /**
   * Check if a window matching the pattern is currently visible.
   * @param titlePattern - Pattern to match in window title
   * @returns true if a matching window exists
   */
  async isWindowVisible(titlePattern?: string): Promise<boolean> {
    const pattern = titlePattern ?? this.defaultTitlePattern;
    
    try {
      const windows = await getWindows();
      
      for (const windowHandle of windows) {
        try {
          const windowRef = new Window(windowHandle);
          const title = await windowRef.getTitle();
          
          if (title.toLowerCase().includes(pattern.toLowerCase())) {
            return true;
          }
        } catch {
          continue;
        }
      }
      
      return false;
    } catch {
      return false;
    }
  }

  /**
   * Get the bounds of a window matching the pattern.
   * Useful for targeted screen capture.
   * @param titlePattern - Pattern to match in window title
   * @returns ScreenRegion of the window, or null if not found
   */
  async getWindowBounds(titlePattern?: string): Promise<ScreenRegion | null> {
    const pattern = titlePattern ?? this.defaultTitlePattern;
    
    try {
      const windows = await getWindows();
      
      for (const windowHandle of windows) {
        try {
          const windowRef = new Window(windowHandle);
          const title = await windowRef.getTitle();
          
          if (title.toLowerCase().includes(pattern.toLowerCase())) {
            const region = await windowRef.getRegion();
            
            return {
              x: region.left,
              y: region.top,
              width: region.width,
              height: region.height,
            };
          }
        } catch {
          continue;
        }
      }
      
      return null;
    } catch (error) {
      this.logger.error('Failed to get window bounds', error instanceof Error ? error : new Error(String(error)));
      return null;
    }
  }

  /**
   * Set the default title pattern for window searches.
   */
  setDefaultTitlePattern(pattern: string): void {
    this.defaultTitlePattern = pattern;
  }

  /**
   * Get the current default title pattern.
   */
  getDefaultTitlePattern(): string {
    return this.defaultTitlePattern;
  }
}