#!/usr/bin/env python3
"""
DaVinci Resolve MCP Server - Application Control Utilities

This module provides functions for controlling DaVinci Resolve application:
- Quitting the application
- Checking application state
- Handling basic application functions
"""

import os
import logging
import time
import sys
import platform
import subprocess
from typing import Dict, Any, Optional, Union, List

# Configure logging
logger = logging.getLogger("davinci-resolve-mcp.app_control")
APP_CONTROL_TIMEOUT_SECONDS = 10


def _run_app_command(
    cmd: List[str],
    description: str,
    timeout: int = APP_CONTROL_TIMEOUT_SECONDS,
) -> bool:
    """Run a platform app-control command with a bounded wait."""
    try:
        result = subprocess.run(
            cmd,
            check=False,
            capture_output=True,
            text=True,
            timeout=timeout,
        )
    except subprocess.TimeoutExpired:
        logger.error("%s timed out after %ss: %s", description, timeout, cmd)
        return False
    except OSError as exc:
        logger.error("%s failed to launch: %s", description, exc)
        return False

    if result.returncode != 0:
        stderr = (result.stderr or "").strip()
        logger.warning(
            "%s exited with code %s%s",
            description,
            result.returncode,
            f": {stderr}" if stderr else "",
        )
        return False
    return True


def quit_resolve_app(resolve_obj, force: bool = False, save_project: bool = True) -> bool:
    """
    Quit DaVinci Resolve application.
    
    Args:
        resolve_obj: DaVinci Resolve API object
        force: Whether to force quit even if unsaved changes (potentially dangerous)
        save_project: Whether to save the project before quitting
        
    Returns:
        True if the quit command was sent successfully
    """
    try:
        logger.info("Attempting to quit DaVinci Resolve")
        
        # Check if a project is open
        pm = resolve_obj.GetProjectManager()
        if pm:
            project = pm.GetCurrentProject()
            if project and save_project:
                logger.info("Saving project before quitting")
                # Try to save the project
                try:
                    project.SaveProject()
                except Exception as e:
                    logger.error(f"Failed to save project: {str(e)}")
                    if not force:
                        logger.error("Aborting quit due to save failure")
                        return False
        
        # Attempt to quit using the API
        if hasattr(resolve_obj, 'Quit') and callable(getattr(resolve_obj, 'Quit')):
            logger.info("Using Resolve.Quit() API")
            resolve_obj.Quit()
            return True
        
        # If Quit method isn't available or fails, use platform-specific methods
        sys_platform = platform.system().lower()
        
        if sys_platform == 'darwin':
            # macOS - use AppleScript
            logger.info("Using AppleScript to quit Resolve on macOS")
            cmd = [
                'osascript',
                '-e', 'tell application "DaVinci Resolve" to quit'
            ]
            if force:
                # Add force option if requested
                cmd = [
                    'osascript',
                    '-e', 'tell application "DaVinci Resolve" to quit with saving'
                ]
            
            return _run_app_command(cmd, "macOS Resolve quit command")
            
        elif sys_platform == 'windows':
            # Windows - use taskkill
            logger.info("Using taskkill to quit Resolve on Windows")
            if force:
                return _run_app_command(
                    ['taskkill', '/F', '/IM', 'Resolve.exe'],
                    "Windows Resolve force-quit command",
                )
            else:
                return _run_app_command(
                    ['taskkill', '/IM', 'Resolve.exe'],
                    "Windows Resolve quit command",
                )
            
        elif sys_platform == 'linux':
            # Linux - use pkill
            logger.info("Using pkill to quit Resolve on Linux")
            if force:
                return _run_app_command(
                    ['pkill', '-9', 'resolve'],
                    "Linux Resolve force-quit command",
                )
            else:
                return _run_app_command(
                    ['pkill', 'resolve'],
                    "Linux Resolve quit command",
                )
            
        # If all methods fail, return False
        logger.error("Failed to quit Resolve via any method")
        return False
        
    except Exception as e:
        logger.error(f"Error quitting DaVinci Resolve: {str(e)}")
        return False

def get_app_state(resolve_obj) -> Dict[str, Any]:
    """
    Get DaVinci Resolve application state information.
    
    Args:
        resolve_obj: DaVinci Resolve API object
        
    Returns:
        Dictionary with application state information
    """
    state = {
        "connected": resolve_obj is not None,
        "version": "Unknown",
        "product_name": "Unknown",
        "platform": platform.system(),
        "python_version": sys.version,
    }
    
    if resolve_obj:
        try:
            state["version"] = resolve_obj.GetVersionString()
        except Exception:
            logger.debug("Could not read Resolve version string", exc_info=True)
            
        try:
            state["product_name"] = resolve_obj.GetProductName()
        except Exception:
            logger.debug("Could not read Resolve product name", exc_info=True)
            
        try:
            state["current_page"] = resolve_obj.GetCurrentPage()
        except Exception:
            logger.debug("Could not read Resolve current page", exc_info=True)
            state["current_page"] = "Unknown"
            
        # Get project manager and project information
        try:
            pm = resolve_obj.GetProjectManager()
            if pm:
                state["project_manager_available"] = True
                
                current_project = pm.GetCurrentProject()
                if current_project:
                    state["project_open"] = True
                    state["project_name"] = current_project.GetName()
                    
                    # Check if timeline is open
                    current_timeline = current_project.GetCurrentTimeline()
                    if current_timeline:
                        state["timeline_open"] = True
                        state["timeline_name"] = current_timeline.GetName()
                    else:
                        state["timeline_open"] = False
                else:
                    state["project_open"] = False
            else:
                state["project_manager_available"] = False
        except Exception as e:
            state["project_error"] = str(e)
    
    return state

def restart_resolve_app(resolve_obj, wait_seconds: int = 5) -> bool:
    """
    Restart DaVinci Resolve application.
    
    Args:
        resolve_obj: DaVinci Resolve API object
        wait_seconds: Seconds to wait between quit and restart
        
    Returns:
        True if restart was initiated successfully
    """
    try:
        # Get Resolve executable path for restart
        if platform.system().lower() == 'darwin':
            resolve_path = '/Applications/DaVinci Resolve/DaVinci Resolve.app'
        elif platform.system().lower() == 'windows':
            # Default path, may need to be customized
            resolve_path = r'C:\Program Files\Blackmagic Design\DaVinci Resolve\Resolve.exe'
        elif platform.system().lower() == 'linux':
            # Default path, may need to be customized
            resolve_path = '/opt/resolve/bin/resolve'
        else:
            return False
        
        # Quit Resolve
        if not quit_resolve_app(resolve_obj, force=False, save_project=True):
            logger.error("Failed to quit Resolve for restart")
            return False
        
        # Wait for the app to close
        logger.info(f"Waiting {wait_seconds} seconds for Resolve to close")
        time.sleep(wait_seconds)
        
        # Start Resolve again
        logger.info("Attempting to start Resolve")
        
        if platform.system().lower() == 'darwin':
            subprocess.Popen(['open', resolve_path])
        elif platform.system().lower() == 'windows':
            subprocess.Popen([resolve_path])
        elif platform.system().lower() == 'linux':
            subprocess.Popen([resolve_path])
        
        return True
    except Exception as e:
        logger.error(f"Error restarting DaVinci Resolve: {str(e)}")
        return False

def open_project_settings(resolve_obj) -> bool:
    """
    Open the Project Settings dialog in DaVinci Resolve.
    
    Args:
        resolve_obj: DaVinci Resolve API object
        
    Returns:
        True if successful, False otherwise
    """
    try:
        # Check if UI Manager is available
        ui_manager = resolve_obj.GetUIManager()
        if not ui_manager:
            logger.error("Failed to get UI Manager")
            return False
        
        # Open Project Settings dialog
        if hasattr(ui_manager, 'OpenProjectSettings') and callable(getattr(ui_manager, 'OpenProjectSettings')):
            ui_manager.OpenProjectSettings()
            return True
        
        # Alternative method - send keyboard shortcut based on platform
        current_page = resolve_obj.GetCurrentPage()
        
        # Ensure we're on a page that supports project settings
        if current_page not in ['media', 'cut', 'edit', 'fusion', 'color', 'fairlight', 'deliver']:
            logger.error(f"Can't open settings from page: {current_page}")
            return False
        
        return False  # Keyboard shortcuts not implemented yet
    except Exception as e:
        logger.error(f"Error opening project settings: {str(e)}")
        return False

def open_preferences(resolve_obj) -> bool:
    """
    Open the Preferences dialog in DaVinci Resolve.
    
    Args:
        resolve_obj: DaVinci Resolve API object
        
    Returns:
        True if successful, False otherwise
    """
    try:
        # Check if UI Manager is available
        ui_manager = resolve_obj.GetUIManager()
        if not ui_manager:
            logger.error("Failed to get UI Manager")
            return False
        
        # Open Preferences dialog
        if hasattr(ui_manager, 'OpenPreferences') and callable(getattr(ui_manager, 'OpenPreferences')):
            ui_manager.OpenPreferences()
            return True
        
        # Alternative method - send keyboard shortcut based on platform
        return False  # Keyboard shortcuts not implemented yet
    except Exception as e:
        logger.error(f"Error opening preferences: {str(e)}")
        return False
