"""
Microsoft Edge Connector for MCP Gateway
Provides Microsoft Edge browser automation and chromeless launching capabilities
"""

import logging
import subprocess
import tempfile
import os
import platform
from typing import Dict, List, Any, Optional

from core.base_connector import BaseConnector
from core.models import ToolDefinition
from core.resource_models import ResourceDefinition

logger = logging.getLogger(__name__)


class EdgeConnector(BaseConnector):
    """Microsoft Edge browser automation connector."""

    def __init__(self, name: str = "edge", config: Dict[str, Any] = None):
        super().__init__(name, config or {})
        self.is_macos = platform.system() == 'Darwin'
        self.edge_path = self._find_edge_executable()

    def _find_edge_executable(self) -> str:
        """Find the Microsoft Edge executable path based on the platform."""
        if self.is_macos:
            return "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
        else:
            # Linux/Windows paths
            for path in [
                "/usr/bin/microsoft-edge",
                "/usr/bin/microsoft-edge-stable",
                "/opt/microsoft/msedge/msedge",
                "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
                "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
            ]:
                if os.path.exists(path):
                    return path
        return "microsoft-edge"  # Fallback to PATH

    def get_tools(self) -> List[ToolDefinition]:
        """Return the tools provided by this connector."""
        return [
            ToolDefinition(
                name="edge_launch_chromeless",
                description="Launch Microsoft Edge in chromeless mode for dashboard viewing. Replaces existing Edge dashboard instances by default.",
                input_schema={
                    "type": "object",
                    "properties": {
                        "url": {
                            "type": "string",
                            "description": "URL to open in chromeless mode",
                            "default": "http://localhost:8090"
                        },
                        "mode": {
                            "type": "string",
                            "enum": ["kiosk", "app", "fullscreen"],
                            "description": "Launch mode: 'kiosk' (full kiosk), 'app' (chromeless window - default), 'fullscreen' (fullscreen window)",
                            "default": "app"
                        },
                        "single_instance": {
                            "type": "boolean",
                            "description": "Replace existing Edge dashboard instances (default: true)",
                            "default": True
                        },
                        "disable_security": {
                            "type": "boolean",
                            "description": "Disable web security for local development (default: true)",
                            "default": True
                        },
                        "user_data_dir": {
                            "type": "string",
                            "description": "Custom user data directory (optional, uses ~/.edge_dashboard for single instance)"
                        },
                        "additional_flags": {
                            "type": "array",
                            "items": {"type": "string"},
                            "description": "Additional Edge command line flags"
                        }
                    },
                    "required": []
                }
            ),
            ToolDefinition(
                name="edge_launch_app",
                description="Launch Microsoft Edge in app mode (chromeless window) for a specific URL",
                input_schema={
                    "type": "object",
                    "properties": {
                        "url": {
                            "type": "string",
                            "description": "URL to open as Edge app"
                        },
                        "window_size": {
                            "type": "string",
                            "description": "Window size (e.g., '1920,1080')",
                            "default": "1920,1080"
                        },
                        "window_position": {
                            "type": "string",
                            "description": "Window position (e.g., '0,0')"
                        }
                    },
                    "required": ["url"]
                }
            ),
            ToolDefinition(
                name="edge_kill_processes",
                description="Kill Microsoft Edge processes (useful for cleanup)",
                input_schema={
                    "type": "object",
                    "properties": {
                        "force": {
                            "type": "boolean",
                            "description": "Force kill Edge processes (default: false)",
                            "default": False
                        },
                        "dashboard_only": {
                            "type": "boolean", 
                            "description": "Kill only dashboard Edge instances (default: false)",
                            "default": False
                        }
                    },
                    "required": []
                }
            ),
            ToolDefinition(
                name="edge_list_dashboard_processes",
                description="List Microsoft Edge processes running with dashboard user data directory",
                input_schema={
                    "type": "object",
                    "properties": {},
                    "required": []
                }
            )
        ]

    def get_resources(self) -> List[ResourceDefinition]:
        """Return the resources provided by this connector."""
        return [
            ResourceDefinition(
                uri="edge://running-processes",
                name="Edge Running Processes",
                description="List of running Microsoft Edge processes",
                mimeType="application/json"
            )
        ]

    def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Execute a tool with the given arguments."""
        try:
            if tool_name == "edge_launch_chromeless":
                return self._launch_chromeless(arguments)
            elif tool_name == "edge_launch_app":
                return self._launch_app(arguments)
            elif tool_name == "edge_kill_processes":
                return self._kill_processes(arguments)
            elif tool_name == "edge_list_dashboard_processes":
                return self._get_dashboard_edge_processes()
            else:
                return {"error": f"Unknown tool: {tool_name}"}
                
        except Exception as e:
            logger.error(f"Error executing {tool_name}: {str(e)}")
            return {"error": str(e)}

    def _launch_chromeless(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Launch Microsoft Edge in chromeless mode with single instance management."""
        url = arguments.get("url", "http://localhost:8090")
        mode = arguments.get("mode", "app")  # Default to app mode instead of kiosk
        disable_security = arguments.get("disable_security", True)
        user_data_dir = arguments.get("user_data_dir")
        additional_flags = arguments.get("additional_flags", [])
        single_instance = arguments.get("single_instance", True)

        # Check for existing dashboard Edge processes and terminate them if single_instance is True
        if single_instance:
            existing_processes = self._get_dashboard_edge_processes()
            if existing_processes.get("count", 0) > 0:
                logger.info(f"Found {existing_processes['count']} existing dashboard Edge processes, terminating them...")
                # Kill specific dashboard processes
                for pid in existing_processes.get("dashboard_processes", []):
                    try:
                        import signal
                        os.kill(pid, signal.SIGTERM)
                        logger.info(f"Terminated Edge process PID: {pid}")
                    except ProcessLookupError:
                        logger.info(f"Process PID {pid} already terminated")
                    except Exception as e:
                        logger.warning(f"Failed to terminate process PID {pid}: {e}")
                
                # Small delay to ensure processes are fully terminated
                import time
                time.sleep(1)

        # Use a consistent user data directory for single instance mode
        if not user_data_dir:
            if single_instance:
                # Use a consistent directory name for single instance
                user_data_dir = os.path.expanduser("~/.edge_dashboard")
                os.makedirs(user_data_dir, exist_ok=True)
            else:
                user_data_dir = tempfile.mkdtemp(prefix="edge_instance_")

        # Build Edge command line arguments
        cmd = [self.edge_path]
        
        # Mode-specific flags - prefer app mode for better window management
        if mode == "kiosk":
            cmd.extend(["--kiosk", url])
        elif mode == "app":
            cmd.extend([f"--app={url}"])
        elif mode == "fullscreen":
            cmd.extend(["--start-fullscreen", url])
        else:
            # Default to app mode if mode is invalid
            cmd.extend([f"--app={url}"])
        
        # Common flags for chromeless operation
        cmd.extend([
            f"--user-data-dir={user_data_dir}",
            "--no-first-run",
            "--no-default-browser-check",
            "--disable-default-apps",
            "--disable-popup-blocking",
            "--disable-translate",
            "--disable-background-timer-throttling",
            "--disable-renderer-backgrounding",
            "--disable-backgrounding-occluded-windows",
            "--disable-ipc-flooding-protection"
        ])
        
        # Security flags for local development
        if disable_security:
            cmd.extend([
                "--disable-web-security",
                "--disable-features=VizDisplayCompositor",
                "--allow-running-insecure-content"
            ])
        
        # Add any additional flags
        cmd.extend(additional_flags)
        
        try:
            # Launch Edge in the background
            logger.info(f"Launching single Edge instance with command: {' '.join(cmd)}")
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                start_new_session=True
            )
            
            return {
                "success": True,
                "url": url,
                "mode": mode,
                "pid": process.pid,
                "user_data_dir": user_data_dir,
                "command": ' '.join(cmd),
                "single_instance": single_instance,
                "message": f"Microsoft Edge launched in {mode} mode (single instance: {single_instance})"
            }
            
        except Exception as e:
            return {
                "success": False,
                "error": f"Failed to launch Microsoft Edge: {str(e)}"
            }

    def _launch_app(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Launch Microsoft Edge in app mode for a specific URL."""
        url = arguments["url"]
        window_size = arguments.get("window_size", "1920,1080")
        window_position = arguments.get("window_position")
        
        # Create temporary user data directory
        user_data_dir = tempfile.mkdtemp(prefix="edge_app_")
        
        cmd = [
            self.edge_path,
            f"--app={url}",
            f"--user-data-dir={user_data_dir}",
            f"--window-size={window_size}",
            "--no-first-run",
            "--no-default-browser-check",
            "--disable-default-apps"
        ]
        
        if window_position:
            cmd.append(f"--window-position={window_position}")
        
        try:
            logger.info(f"Launching Edge app: {' '.join(cmd)}")
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                start_new_session=True
            )
            
            return {
                "success": True,
                "url": url,
                "mode": "app",
                "pid": process.pid,
                "window_size": window_size,
                "window_position": window_position,
                "user_data_dir": user_data_dir
            }
            
        except Exception as e:
            return {
                "success": False,
                "error": f"Failed to launch Edge app: {str(e)}"
            }

    def _kill_processes(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Kill Microsoft Edge processes."""
        force = arguments.get("force", False)
        dashboard_only = arguments.get("dashboard_only", False)
        
        try:
            if dashboard_only:
                # Kill only dashboard Edge processes
                dashboard_processes = self._get_dashboard_edge_processes()
                if dashboard_processes.get("count", 0) == 0:
                    return {
                        "success": True,
                        "message": "No dashboard Edge processes found to terminate",
                        "dashboard_only": True
                    }
                
                terminated_pids = []
                for pid in dashboard_processes.get("dashboard_processes", []):
                    try:
                        import signal
                        if force:
                            os.kill(pid, signal.SIGKILL)
                        else:
                            os.kill(pid, signal.SIGTERM)
                        terminated_pids.append(pid)
                    except ProcessLookupError:
                        pass  # Process already terminated
                    except Exception as e:
                        logger.warning(f"Failed to terminate dashboard process PID {pid}: {e}")
                
                return {
                    "success": True,
                    "message": f"Terminated {len(terminated_pids)} dashboard Edge processes",
                    "terminated_pids": terminated_pids,
                    "dashboard_only": True,
                    "force": force
                }
            else:
                # Kill all Edge processes (original behavior)
                if self.is_macos:
                    if force:
                        cmd = ["killall", "-9", "Microsoft Edge"]
                    else:
                        cmd = ["killall", "Microsoft Edge"]
                else:
                    if force:
                        cmd = ["pkill", "-9", "-f", "msedge"]
                    else:
                        cmd = ["pkill", "-f", "msedge"]
                
                result = subprocess.run(cmd, capture_output=True, text=True)
                
                if result.returncode == 0:
                    return {
                        "success": True,
                        "message": "All Edge processes terminated",
                        "dashboard_only": False,
                        "force": force
                    }
                elif result.returncode == 1:
                    return {
                        "success": True,
                        "message": "No Edge processes found to terminate",
                        "dashboard_only": False,
                        "force": force
                    }
                else:
                    return {
                        "success": False,
                        "error": f"Failed to kill Edge processes: {result.stderr}",
                        "dashboard_only": False,
                        "force": force
                    }
                
        except Exception as e:
            return {
                "success": False,
                "error": f"Error killing Edge processes: {str(e)}"
            }

    def read_resource(self, uri: str) -> Dict[str, Any]:
        """Read a resource by URI."""
        try:
            if uri == "edge://running-processes":
                return self._get_running_processes()
            else:
                return {"error": f"Unknown resource URI: {uri}"}
                
        except Exception as e:
            logger.error(f"Error reading resource {uri}: {str(e)}")
            return {"error": str(e)}

    def _get_running_processes(self) -> Dict[str, Any]:
        """Get list of running Microsoft Edge processes."""
        try:
            if self.is_macos:
                cmd = ["pgrep", "-f", "Microsoft Edge"]
            else:
                cmd = ["pgrep", "-f", "msedge"]
            
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode == 0:
                pids = [int(pid.strip()) for pid in result.stdout.split() if pid.strip()]
                return {
                    "running_processes": pids,
                    "count": len(pids)
                }
            else:
                return {
                    "running_processes": [],
                    "count": 0
                }
                
        except Exception as e:
            return {"error": f"Failed to get Edge processes: {str(e)}"}

    def _get_dashboard_edge_processes(self) -> Dict[str, Any]:
        """Get list of Microsoft Edge processes specifically running with our dashboard user data directory."""
        try:
            dashboard_dir = r"\.edge_dashboard"  # Escape the dot for grep
            
            # Use ps and grep to find processes with our dashboard user data directory
            cmd = ["ps", "aux"]
            ps_result = subprocess.run(cmd, capture_output=True, text=True)
            
            if ps_result.returncode != 0:
                return {"error": "Failed to get process list"}
            
            # Filter for Edge processes with our dashboard directory
            grep_cmd = ["grep", "-E", f"Microsoft Edge.*{dashboard_dir}"]
            grep_process = subprocess.Popen(grep_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            grep_output, _ = grep_process.communicate(input=ps_result.stdout)
            
            # Extract PIDs from the grep output
            pids = []
            for line in grep_output.strip().split('\n'):
                if line and 'grep' not in line:  # Exclude the grep process itself
                    parts = line.split()
                    if len(parts) >= 2:
                        try:
                            pid = int(parts[1])  # PID is typically the second column in ps aux
                            pids.append(pid)
                        except ValueError:
                            continue
            
            return {
                "dashboard_processes": pids,
                "count": len(pids)
            }
                
        except Exception as e:
            return {"error": f"Failed to get dashboard Edge processes: {str(e)}"}