"""MCP server for mobile-use with screen analysis capabilities."""

import argparse
import os
import sys
import threading
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass

# Fix Windows console encoding for Unicode characters (emojis in logs)
if sys.platform == "win32":
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")  # type: ignore[attr-defined]
    if hasattr(sys.stderr, "reconfigure"):
        sys.stderr.reconfigure(encoding="utf-8")  # type: ignore[attr-defined]
    os.environ["PYTHONIOENCODING"] = "utf-8"

    try:
        import colorama

        colorama.init(strip=False, convert=True, wrap=True)
    except ImportError:
        pass


from fastmcp import FastMCP  # noqa: E402

from minitap.mcp.core.config import settings  # noqa: E402
from minitap.mcp.core.device import (
    DeviceInfo,  # noqa: E402
    list_available_devices,
)
from minitap.mcp.core.logging_config import (
    configure_logging,  # noqa: E402
    get_logger,
)
from minitap.mcp.server.middleware import LocalDeviceHealthMiddleware
from minitap.mcp.server.poller import device_health_poller
from minitap.mobile_use.config import settings as sdk_settings

configure_logging(log_level=os.getenv("LOG_LEVEL", "INFO"))


def main() -> None:
    """Main entry point for the MCP server."""

    parser = argparse.ArgumentParser(description="Mobile Use MCP Server")
    parser.add_argument(
        "--api-key",
        type=str,
        required=False,
        default=None,
        help="Minitap API key for authentication",
    )

    parser.add_argument("--llm-profile", type=str, required=False, default=None)
    parser.add_argument(
        "--server",
        action="store_true",
        help="Run as network server (uses MCP_SERVER_HOST and MCP_SERVER_PORT from env)",
    )
    parser.add_argument(
        "--port",
        type=int,
        required=False,
        default=None,
        help="Port to run the server on (overrides MCP_SERVER_PORT env variable)",
    )

    args = parser.parse_args()

    if args.api_key:
        os.environ["MINITAP_API_KEY"] = args.api_key
        settings.__init__()
        sdk_settings.__init__()

    if args.llm_profile:
        os.environ["MINITAP_LLM_PROFILE_NAME"] = args.llm_profile
        settings.__init__()
        sdk_settings.__init__()

    if args.port:
        os.environ["MCP_SERVER_PORT"] = str(args.port)
        settings.__init__()
        sdk_settings.__init__()

    if not settings.MINITAP_API_KEY:
        raise ValueError("Minitap API key is required to run the MCP")

    # Run MCP server with optional host/port for remote access
    if args.server:
        logger.info(f"Starting MCP server on {settings.MCP_SERVER_HOST}:{settings.MCP_SERVER_PORT}")
        run_mcp_server(
            transport="http",
            host=settings.MCP_SERVER_HOST,
            port=settings.MCP_SERVER_PORT,
        )
    else:
        logger.info("Starting MCP server in local mode")
        run_mcp_server()


logger = get_logger(__name__)


@dataclass
class MCPLifespanContext:
    """Context for MCP server lifespan.

    Stores references to services that need cleanup on shutdown.
    """

    local_poller_stop_event: threading.Event | None = None
    local_poller_thread: threading.Thread | None = None
    remote_mcp_proxy: FastMCP | None = None


@asynccontextmanager
async def mcp_lifespan(server: FastMCP) -> AsyncIterator[MCPLifespanContext]:
    """Lifespan context manager for MCP server.

    Handles startup/shutdown for local and cloud-only modes.

    Local mode (ENABLE_LOCAL_DEVICE=True, default):
    - Starts device health poller
    - Monitors local device connection

    Cloud-only mode (ENABLE_LOCAL_DEVICE=False):
    - No local device polling
    - Use cloud_platform parameter in execute_mobile_command to run tasks

    Args:
        server: The FastMCP server instance.

    Yields:
        MCPLifespanContext with references to running services.
    """
    from minitap.mcp.core.sdk_agent import get_mobile_use_agent  # noqa: E402

    context = MCPLifespanContext()
    api_key = settings.MINITAP_API_KEY.get_secret_value() if settings.MINITAP_API_KEY else None

    if settings.ENABLE_LOCAL_DEVICE:
        # ==================== LOCAL MODE ====================
        logger.info("Starting MCP in LOCAL mode with device polling")

        agent = get_mobile_use_agent()
        server.add_middleware(LocalDeviceHealthMiddleware(agent))

        # Start device health poller in background
        stop_event = threading.Event()
        poller_thread = threading.Thread(
            target=device_health_poller,
            args=(stop_event, agent),
            daemon=True,
        )
        poller_thread.start()

        context.local_poller_stop_event = stop_event
        context.local_poller_thread = poller_thread
        logger.info("Device health poller started")
    else:
        # ==================== CLOUD-ONLY MODE ====================
        logger.info(
            "Starting MCP without local device polling (ENABLE_LOCAL_DEVICE=False). "
            "Use cloud_platform parameter in execute_mobile_command to run tasks."
        )

    # ==================== REMOTE MCP PROXY ====================
    # Mount remote MCP proxy if configured (works in both cloud and local modes)
    if settings.MINITAP_API_MCP_BASE_URL and api_key:
        from minitap.mcp.server.remote_proxy import (
            check_remote_mcp_availability,
            create_remote_mcp_proxy,
        )

        logger.info(f"Attempting to connect to remote MCP at: {settings.MINITAP_API_MCP_BASE_URL}")

        try:
            is_available = await check_remote_mcp_availability(
                mcp_url=settings.MINITAP_API_MCP_BASE_URL,
                api_key=api_key,
            )

            if is_available:
                remote_proxy = create_remote_mcp_proxy(
                    mcp_url=settings.MINITAP_API_MCP_BASE_URL,
                    api_key=api_key,
                    prefix="",
                )

                server.mount(remote_proxy)
                logger.info("Remote MCP proxy mounted successfully without prefix")

                context.remote_mcp_proxy = remote_proxy
            else:
                logger.warning(
                    "Remote MCP server is not available. "
                    "Local tools will remain functional, but remote tools (Figma, Jira) "
                    "will not be accessible."
                )
        except Exception as e:
            # Log warning but don't crash - local tools should remain functional
            logger.warning(
                f"Failed to create remote MCP proxy: {e}. "
                "Local tools will remain functional, but remote tools will not be accessible."
            )

    try:
        yield context
    finally:
        # ==================== SHUTDOWN ====================
        logger.info("MCP server shutting down, cleaning up resources...")

        if context.local_poller_stop_event and context.local_poller_thread:
            # Stop local device health poller
            logger.info("Stopping device health poller...")
            context.local_poller_stop_event.set()
            context.local_poller_thread.join(timeout=10.0)

            if context.local_poller_thread.is_alive():
                logger.warning("Device health poller thread did not stop gracefully")
            else:
                logger.info("Device health poller stopped successfully")

        # Clean up remote MCP proxy connection
        # basically not super important for now, but will be in the
        # future when cloud dependencies must be cleaned up
        if context.remote_mcp_proxy:
            try:
                logger.info("Cleaning up remote MCP proxy connection")
                context.remote_mcp_proxy = None
            except Exception as e:
                logger.warning(f"Error cleaning up remote MCP proxy: {e}")

        logger.info("MCP server shutdown complete")


# Create MCP server with lifespan handler
mcp = FastMCP(
    name="mobile-use-mcp",
    instructions="""
        This server provides analysis tools for connected
        mobile devices (iOS or Android).
        Call get_available_devices() to list them.
    """,
    lifespan=mcp_lifespan,
)

from minitap.mcp.tools import (  # noqa: E402
    execute_mobile_command,  # noqa: E402, F401
    read_swift_logs,  # noqa: E402, F401
    upload_screenshot,  # noqa: E402, F401
)


@mcp.resource("data://devices")
def get_available_devices() -> list[DeviceInfo]:
    """Provides a list of connected mobile devices (iOS or Android)."""
    return list_available_devices()


def run_mcp_server(**mcp_run_kwargs):
    """Run the MCP server with proper exception handling.

    This wraps mcp.run() with exception handling for clean shutdown.
    """
    try:
        mcp.run(**mcp_run_kwargs)
    except KeyboardInterrupt:
        logger.info("Keyboard interrupt received, shutting down...")
    except Exception as e:
        logger.error(f"Error running MCP server: {e}")
        raise
