#!/usr/bin/env python3
"""
Minimize All Windows - Python Version (Fixed)
Requires: pip3 install pyobjc-framework-Cocoa pyobjc-framework-Quartz

This uses native macOS APIs which should be more reliable than AppleScript.
"""

import time
from Cocoa import NSWorkspace
from Quartz import (
    CGWindowListCopyWindowInfo,
    kCGWindowListOptionOnScreenOnly,
    kCGNullWindowID,
    kCGWindowListExcludeDesktopElements
)
import subprocess


def get_apps_with_visible_windows():
    """Get set of app names that have actual visible on-screen windows"""
    window_list = CGWindowListCopyWindowInfo(
        kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
        kCGNullWindowID
    )
    
    apps_with_windows = set()
    
    for window in window_list:
        # Get the owning application name
        owner_name = window.get('kCGWindowOwnerName', '')
        
        # Check if window is actually visible and has size
        # Layer 0 = normal windows, skip menu bar items etc.
        layer = window.get('kCGWindowLayer', 0)
        bounds = window.get('kCGWindowBounds', {})
        width = bounds.get('Width', 0)
        height = bounds.get('Height', 0)
        
        # Only count windows that are on the normal layer and have reasonable size
        # (filters out menu bar, dock, status items, etc.)
        if layer == 0 and width > 50 and height > 50 and owner_name:
            apps_with_windows.add(owner_name)
    
    return apps_with_windows


def minimize_window_via_applescript(app_name):
    """Use AppleScript to minimize the frontmost window of an app"""
    script = f'''
    tell application "{app_name}"
        activate
    end tell
    delay 0.8
    tell application "System Events"
        tell process "{app_name}"
            set frontmost to true
            delay 0.4
            keystroke "m" using command down
        end tell
    end tell
    '''
    try:
        subprocess.run(['osascript', '-e', script], timeout=5, check=False)
        return True
    except Exception as e:
        print(f"Failed to minimize {app_name}: {e}")
        return False


# Apps that don't respond to Cmd+M and need special handling
# Maps app display name -> process name (as seen by System Events)
EXCEPTION_APPS = {
    'Spyder 6': 'python',
    'MacVim': 'MacVim',
    # Add more exception apps here as needed, e.g.:
    # 'SomeApp': 'some_process_name',
}


def minimize_exception_app(app_name, process_name):
    """
    Minimize windows for apps that don't respond to Cmd+M.
    Uses the AXMinimized accessibility attribute directly.
    """
    script = f'''
    tell application "System Events"
        tell process "{process_name}"
            set windowCount to count of windows
            if windowCount > 0 then
                repeat with w in windows
                    try
                        -- Only minimize if not already minimized
                        if value of attribute "AXMinimized" of w is false then
                            set value of attribute "AXMinimized" of w to true
                        end if
                    end try
                end repeat
            end if
            return windowCount
        end tell
    end tell
    '''
    try:
        result = subprocess.run(
            ['osascript', '-e', script],
            capture_output=True,
            text=True,
            timeout=10
        )
        window_count = result.stdout.strip()
        print(f"{app_name}: Minimized via AXMinimized (windows: {window_count})")
        return True
    except Exception as e:
        print(f"Failed to minimize {app_name} via AXMinimized: {e}")
        return False


def minimize_finder_windows():
    """Minimize all Finder windows using Finder's native scripting"""
    # First, get count of non-collapsed Finder windows
    count_script = '''
    tell application "Finder"
        set visibleWindows to (every Finder window whose collapsed is false)
        return count of visibleWindows
    end tell
    '''
    try:
        result = subprocess.run(
            ['osascript', '-e', count_script],
            capture_output=True,
            text=True,
            timeout=5
        )
        window_count = int(result.stdout.strip()) if result.stdout.strip() else 0
        
        if window_count == 0:
            print("Finder: No visible windows to minimize")
            return
        
        print(f"Finder: Minimizing {window_count} window(s)")
        
        # Finder uses "collapsed" not "miniaturized" for minimizing windows
        minimize_script = '''
        tell application "Finder"
            set allWindows to every Finder window
            repeat with w in allWindows
                set collapsed of w to true
            end repeat
        end tell
        '''
        subprocess.run(['osascript', '-e', minimize_script], timeout=10, check=False)
        
    except Exception as e:
        print(f"Failed to minimize Finder windows: {e}")


def main():
    # Apps to skip - these either don't have minimizable windows or cause issues
    skip_apps = {'SystemUIServer', 'Dock', 'Electron', 'MSTeams', 'nxdock', 
                 'Control Center', 'Notification Center', 'Spotlight',
                 # User-specified apps to never minimize
                 'Teams', 'Microsoft Teams', 'Ferdium', 'Messages', 'iMessage',
                 'Grasshopper', 'Outlook', 'Microsoft Outlook', 'Wavebox',
                 'iTerm2'}
    # 'Claude', 'Copilot', 'GitHub', 'GitHub Desktop',  
    skip_keywords = ['Helper', 'Agent']
    
    # FIX #1: Get only apps that actually have visible windows on screen
    apps_with_windows = get_apps_with_visible_windows()
    print(f"Apps with visible windows: {apps_with_windows}")
    
    # FIX #2: Handle Finder separately and skip it in main loop
    # Remove Finder from the set - we'll handle it specially
    apps_with_windows.discard('Finder')
    
    # Also remove exception apps from the main loop - we'll handle them separately
    for exception_app in EXCEPTION_APPS.keys():
        apps_with_windows.discard(exception_app)
    
    # Get all running applications (to get proper app objects)
    workspace = NSWorkspace.sharedWorkspace()
    running_apps = workspace.runningApplications()
    
    processed_apps = set()
    
    for app in running_apps:
        app_name = app.localizedName()
        
        # Skip if already processed
        if app_name in processed_apps:
            continue
        
        # FIX #1: Skip if this app doesn't have visible windows
        if app_name not in apps_with_windows:
            continue
            
        # Skip exception apps - they're handled separately
        if app_name in EXCEPTION_APPS:
            continue
            
        # Skip system apps and problematic apps
        if app_name in skip_apps:
            continue
            
        # Skip apps with certain keywords
        if any(keyword in app_name for keyword in skip_keywords):
            continue
            
        # Skip if not a regular app
        if not app.activationPolicy() == 0:  # NSApplicationActivationPolicyRegular
            continue
            
        print(f"Processing: {app_name}")
        minimize_window_via_applescript(app_name)
        processed_apps.add(app_name)
        time.sleep(0.3)
    
    # Handle exception apps that don't respond to Cmd+M
    for app_name, process_name in EXCEPTION_APPS.items():
        # Check if this app actually has visible windows
        # We need to re-check since we removed it from apps_with_windows earlier
        check_script = f'''
        tell application "System Events"
            if exists process "{process_name}" then
                tell process "{process_name}"
                    set visibleCount to 0
                    repeat with w in windows
                        try
                            if value of attribute "AXMinimized" of w is false then
                                set visibleCount to visibleCount + 1
                            end if
                        end try
                    end repeat
                    return visibleCount
                end tell
            else
                return 0
            end if
        end tell
        '''
        try:
            result = subprocess.run(
                ['osascript', '-e', check_script],
                capture_output=True,
                text=True,
                timeout=5
            )
            visible_count = int(result.stdout.strip()) if result.stdout.strip() else 0
            if visible_count > 0:
                print(f"Processing exception app: {app_name}")
                minimize_exception_app(app_name, process_name)
                time.sleep(0.3)
        except Exception as e:
            print(f"Error checking {app_name}: {e}")
    
    # FIX #2: Handle Finder windows separately using Finder's native scripting
    # This is more reliable than using Cmd+M
    minimize_finder_windows()
    
    print("Done minimizing all windows")


if __name__ == '__main__':
    main()
