"""
Main FastMCP ESPTool Server

This is the core server that orchestrates all ESP development components using FastMCP.
Provides AI-powered ESP32/ESP8266 development workflows with production-grade capabilities.
"""

import logging
import sys
import time
from typing import Any

import click
from fastmcp import Context, FastMCP
from rich.console import Console
from rich.logging import RichHandler

from .components import (
    ChipControl,
    Diagnostics,
    FirmwareBuilder,
    FlashManager,
    OTAManager,
    PartitionManager,
    ProductionTools,
    QemuManager,
    SecurityManager,
)
from .config import ESPToolServerConfig, get_config, set_config

# Set up rich logging
console = Console()
logging.basicConfig(
    level=logging.INFO,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[RichHandler(console=console, rich_tracebacks=True)],
)

logger = logging.getLogger(__name__)


class ESPToolServer:
    """FastMCP ESPTool Server - AI-powered ESP development"""

    def __init__(self, config: ESPToolServerConfig | None = None):
        """Initialize the ESP Tool Server"""
        self.config = config or get_config()
        set_config(self.config)

        # Initialize FastMCP app
        self.app = FastMCP("ESP Development Server")

        # Component instances
        self.components: dict[str, Any] = {}

        # Server state
        self.startup_time = time.time()

        # Initialize components
        self._initialize_components()
        self._setup_server_info()
        self._setup_resources()

    def _initialize_components(self) -> None:
        """Initialize all ESP development components"""
        logger.info("🔧 Initializing ESP development components...")

        try:
            # Core ESP operations
            self.components["chip_control"] = ChipControl(self.app, self.config)
            self.components["flash_manager"] = FlashManager(self.app, self.config)
            self.components["partition_manager"] = PartitionManager(self.app, self.config)

            # Advanced features
            self.components["security_manager"] = SecurityManager(self.app, self.config)
            self.components["firmware_builder"] = FirmwareBuilder(self.app, self.config)
            self.components["ota_manager"] = OTAManager(self.app, self.config)

            # Production tools
            self.components["production_tools"] = ProductionTools(self.app, self.config)
            self.components["diagnostics"] = Diagnostics(self.app, self.config)

            # QEMU emulation (if available)
            if self.config.get_qemu_available():
                self.components["qemu_manager"] = QemuManager(self.app, self.config)
                logger.info("✅ QEMU emulation enabled")

            # ESP-IDF integration (if available)
            if self.config.get_idf_available():
                from .components.idf_integration import IDFIntegration

                self.components["idf_integration"] = IDFIntegration(self.app, self.config)
                logger.info("✅ ESP-IDF integration enabled")

            # Cross-wire: let ChipControl see QEMU instances for scan integration
            if "qemu_manager" in self.components:
                self.components["chip_control"].qemu_manager = self.components["qemu_manager"]

            logger.info(f"✅ Initialized {len(self.components)} components")

        except Exception as e:
            logger.error(f"❌ Failed to initialize components: {e}")
            raise

    def _setup_server_info(self) -> None:
        """Set up server information and metadata tools"""

        @self.app.tool("esp_server_info")
        async def server_info(context: Context) -> dict[str, Any]:
            """Get comprehensive ESP development server information"""
            uptime = time.time() - self.startup_time

            # Get tool and resource counts via public API
            tools = await self.app.get_tools()
            # Note: FastMCP doesn't expose get_resources(), so we count our components
            resource_count = 3  # esp://server/status, esp://config, esp://capabilities

            return {
                "server_name": "MCP ESPTool Server",
                "version": "2025.09.28.1",
                "uptime_seconds": round(uptime, 2),
                "configuration": self.config.to_dict(),
                "components": list(self.components.keys()),
                "total_tools": len(tools),
                "total_resources": resource_count,
                "esp_idf_available": self.config.get_idf_available(),
                "production_mode": self.config.production_mode,
                "capabilities": {
                    "chip_detection": True,
                    "flash_operations": True,
                    "partition_management": True,
                    "security_features": True,
                    "ota_updates": True,
                    "factory_programming": True,
                    "host_applications": self.config.get_idf_available(),
                    "qemu_emulation": self.config.get_qemu_available(),
                },
            }

        @self.app.tool("esp_list_tools")
        async def list_esp_tools(context: Context, category: str | None = None) -> dict[str, Any]:
            """List all available ESP development tools, optionally filtered by category"""

            # Categorize tools by component
            tool_categories = {
                "chip_control": [
                    "esp_detect_chip",
                    "esp_connect_advanced",
                    "esp_reset_chip",
                    "esp_load_test_firmware",
                ],
                "flash_operations": [
                    "esp_flash_firmware",
                    "esp_flash_read",
                    "esp_flash_erase",
                    "esp_flash_backup",
                ],
                "partition_management": [
                    "esp_partition_create_ota",
                    "esp_partition_custom",
                    "esp_partition_analyze",
                ],
                "security": [
                    "esp_security_audit",
                    "esp_enable_flash_encryption",
                    "esp_efuse_read",
                    "esp_efuse_burn",
                ],
                "firmware": ["esp_elf_to_binary", "esp_firmware_analyze"],
                "ota": ["esp_ota_package_create", "esp_ota_deploy", "esp_ota_rollback"],
                "production": ["esp_factory_program", "esp_batch_program", "esp_quality_control"],
                "diagnostics": [
                    "esp_memory_dump",
                    "esp_performance_profile",
                    "esp_diagnostic_report",
                ],
            }

            if self.config.get_qemu_available():
                tool_categories["qemu_emulation"] = [
                    "esp_qemu_start",
                    "esp_qemu_stop",
                    "esp_qemu_list",
                    "esp_qemu_status",
                    "esp_qemu_flash",
                ]

            if self.config.get_idf_available():
                tool_categories["esp_idf"] = [
                    "idf_create_host_project",
                    "idf_build_project",
                    "idf_flash_project",
                    "idf_monitor",
                ]

            if category:
                if category not in tool_categories:
                    return {
                        "error": f"Unknown category: {category}",
                        "available_categories": list(tool_categories.keys()),
                    }
                return {"category": category, "tools": tool_categories[category]}

            return {
                "total_categories": len(tool_categories),
                "categories": tool_categories,
                "total_tools": sum(len(tools) for tools in tool_categories.values()),
            }

        @self.app.tool("esp_health_check")
        async def health_check(context: Context, detailed: bool = False) -> dict[str, Any]:
            """Perform health check of ESP development environment"""

            health_status = {"status": "healthy", "timestamp": time.time(), "checks": {}}

            # Check esptool availability
            try:
                import subprocess

                result = subprocess.run(
                    [self.config.esptool_path, "version"], capture_output=True, text=True, timeout=5
                )
                health_status["checks"]["esptool"] = {
                    "available": result.returncode == 0,
                    "version": result.stdout.strip() if result.returncode == 0 else None,
                }
            except Exception as e:
                health_status["checks"]["esptool"] = {"available": False, "error": str(e)}

            # Check ESP-IDF availability
            if self.config.esp_idf_path:
                health_status["checks"]["esp_idf"] = {
                    "available": self.config.get_idf_available(),
                    "path": str(self.config.esp_idf_path),
                }

            # Check project directories
            health_status["checks"]["project_roots"] = {
                "configured": len(self.config.project_roots),
                "accessible": sum(1 for root in self.config.project_roots if root.exists()),
            }

            # Check component health
            if detailed:
                component_health = {}
                for component_name, component in self.components.items():
                    if hasattr(component, "health_check"):
                        try:
                            component_health[component_name] = await component.health_check()
                        except Exception as e:
                            component_health[component_name] = {"status": "error", "error": str(e)}
                    else:
                        component_health[component_name] = {
                            "status": "ok",
                            "note": "No health check available",
                        }

                health_status["components"] = component_health

            # Determine overall health
            failed_checks = [
                name
                for name, check in health_status["checks"].items()
                if not check.get("available", True)
            ]

            if failed_checks:
                health_status["status"] = "degraded"
                health_status["failed_checks"] = failed_checks

            return health_status

    def _setup_resources(self) -> None:
        """Set up MCP resources for real-time information"""

        @self.app.resource("esp://server/status")
        async def server_status() -> str:
            """Real-time server status information"""
            uptime = time.time() - self.startup_time

            status = {
                "status": "running",
                "uptime_seconds": round(uptime, 2),
                "components_loaded": len(self.components),
                "production_mode": self.config.production_mode,
                "last_updated": time.time(),
            }

            return status

        @self.app.resource("esp://config")
        async def current_config() -> str:
            """Current server configuration"""
            return self.config.to_dict()

        @self.app.resource("esp://capabilities")
        async def server_capabilities() -> str:
            """Server capabilities and feature availability"""
            return {
                "esp_chip_support": [
                    "ESP32",
                    "ESP32-S2",
                    "ESP32-S3",
                    "ESP32-C3",
                    "ESP32-C6",
                    "ESP8266",
                ],
                "flash_operations": ["read", "write", "erase", "verify", "encrypt"],
                "partition_features": ["custom_tables", "ota_support", "nvs_management"],
                "security_features": ["efuse_management", "secure_boot", "flash_encryption"],
                "production_features": [
                    "factory_programming",
                    "batch_operations",
                    "quality_control",
                ],
                "debugging_features": [
                    "memory_dump",
                    "performance_profiling",
                    "diagnostic_reports",
                ],
                "esp_idf_integration": self.config.get_idf_available(),
                "host_applications": self.config.get_idf_available(),
                "qemu_emulation": self.config.get_qemu_available(),
            }

    def run(self, transport: str = "stdio") -> None:
        """
        Run the FastMCP server

        Args:
            transport: Transport type (stdio, sse, http)
        """
        # Log startup information
        logger.info("🚀 Starting ESP Development Server...")
        logger.info(f"📊 Loaded {len(self.components)} components")

        # Check esptool availability
        import subprocess

        try:
            result = subprocess.run(
                [self.config.esptool_path, "version"],
                capture_output=True,
                text=True,
                timeout=5,
            )
            if result.returncode == 0:
                logger.info(f"✅ esptool available: {result.stdout.strip().split()[0]}")
            else:
                logger.warning("⚠️ esptool not available - some features may be limited")
        except (subprocess.TimeoutExpired, FileNotFoundError):
            logger.warning("⚠️ esptool not found - some features may be limited")

        if self.config.get_qemu_available():
            logger.info("🖥️ QEMU emulation available")

        if self.config.get_idf_available():
            logger.info("🏗️ ESP-IDF integration available")

        if self.config.production_mode:
            logger.info("🏭 Running in production mode")
        else:
            logger.info("🛠️ Running in development mode")

        logger.info("✅ Server ready - waiting for MCP connections...")

        # Use FastMCP's built-in run() method
        self.app.run(transport=transport)


# CLI interface
@click.command()
@click.option("--config", "-c", help="Configuration file path")
@click.option("--debug", "-d", is_flag=True, help="Enable debug logging")
@click.option("--production", "-p", is_flag=True, help="Run in production mode")
@click.option("--port", default=8080, help="Server port (for future HTTP interface)")
@click.version_option(version="2025.09.28.1")
def main(config: str | None, debug: bool, production: bool, port: int) -> None:
    """
    FastMCP ESP Development Server

    Provides AI-powered ESP32/ESP8266 development workflows through natural language.
    """
    # Configure logging level
    if debug:
        logging.getLogger().setLevel(logging.DEBUG)
        logger.info("🐛 Debug logging enabled")

    # Load configuration
    if config:
        logger.info(f"📁 Loading configuration from: {config}")
        # TODO: Implement configuration file loading
        server_config = ESPToolServerConfig.from_environment()
    else:
        server_config = ESPToolServerConfig.from_environment()

    # Override production mode if specified
    if production:
        server_config.production_mode = True
        logger.info("🏭 Production mode enabled via CLI")

    # Display startup banner
    console.print("\n[bold blue]🚀 FastMCP ESP Development Server[/bold blue]")
    console.print("[dim]AI-powered ESP32/ESP8266 development workflows[/dim]")
    console.print("[dim]Version: 2025.09.28.1[/dim]")
    console.print()

    # Create and run server
    try:
        server = ESPToolServer(server_config)
        server.run()
    except Exception as e:
        logger.error(f"❌ Failed to start server: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
