"""HealthCheckerRefactored - Split complex health checking into focused components."""

import sys
import shutil
from typing import Any
from abc import ABC, abstractmethod

import structlog

logger = structlog.get_logger()


class HealthCheck(ABC):
    """Base class for specific health checks."""
    
    @abstractmethod
    def check(self, diag: dict[str, Any], tool) -> None:
        """Perform health check and update diag dictionary."""
        pass


class BinaryHealthCheck(HealthCheck):
    """Check if tool binary is available on PATH."""
    
    def check(self, diag: dict[str, Any], tool) -> None:
        """Check binary availability and provide fixes."""
        if not tool.binary:
            return
            
        binary_found = bool(shutil.which(tool.binary))
        diag["binary_found"] = binary_found
        
        if not binary_found:
            self._add_binary_fixes(diag, tool)
    
    def _add_binary_fixes(self, diag: dict[str, Any], tool) -> None:
        """Add appropriate fixes for missing binaries."""
        if tool.name == "aider":
            from proxym.dashboard.tools.utils._aider_install_fix import _aider_install_fix
            diag["issues"].append(f"{tool.binary} binary not found on PATH")
            diag["fixes"].append(_aider_install_fix())
            
        elif tool.name == "claude-code":
            diag["issues"].append(f"{tool.binary} binary not found on PATH")
            diag["fixes"].append({
                "action": "install",
                "label": "Install claude-code",
                "command": "npm install -g @anthropic-ai/claude-code",
                "description": "Install Claude Code CLI tool",
            })
            
        elif tool.name in ("windsurf", "cursor"):
            diag["issues"].append(f"{tool.name} is a desktop IDE — not available in container")
            diag["fixes"].append({
                "action": "info",
                "label": f"{tool.name} runs on host only",
                "command": f"# Install from https://{tool.name}.com — dispatches via echo inside container",
                "description": "Desktop IDE tool — dispatch works but actual execution requires host",
            })


class InstanceHealthCheck(HealthCheck):
    """Check tool instances (Docker, KVM, VM)."""
    
    def check(self, diag: dict[str, Any], tool) -> None:
        """Check availability of different instance types."""
        for inst in tool.instances:
            if inst.kind == "docker" and inst.is_available:
                diag["docker_instance"] = True
                break
            if inst.kind == "kvm" and inst.is_available:
                diag["kvm_instance"] = True
                break
            if inst.kind == "vm" and inst.is_available:
                diag["vm_instance"] = True
                break
        
        # Check for VM-specific issues
        self._check_vm_access(diag, tool)
    
    def _check_vm_access(self, diag: dict[str, Any], tool) -> None:
        """Check VM access for tools that need it."""
        has_vm_instance = any(inst.kind in ("kvm", "vm") for inst in tool.instances)
        if has_vm_instance and not (diag["kvm_instance"] or diag["vm_instance"]):
            vm_inst = next((i for i in tool.instances if i.kind in ("kvm", "vm")), None)
            if vm_inst:
                self._add_vm_fixes(diag, vm_inst)
    
    def _add_vm_fixes(self, diag: dict[str, Any], vm_inst) -> None:
        """Add fixes for VM access issues."""
        if vm_inst.vm_name:
            diag["issues"].append(f"KVM VM '{vm_inst.vm_name}' not running")
            virsh_cmd = f"virsh start {vm_inst.vm_name}" if shutil.which("virsh") else f"# Start VM {vm_inst.vm_name} via your hypervisor"
            diag["fixes"].append({
                "action": "start_vm",
                "label": f"Start {vm_inst.vm_name} VM",
                "command": virsh_cmd,
                "description": f"Start the KVM virtual machine '{vm_inst.vm_name}'",
            })
        elif vm_inst.vm_host:
            diag["issues"].append(f"VM at {vm_inst.vm_host} not reachable via SSH")
            diag["fixes"].append({
                "action": "ssh_check",
                "label": f"Check SSH to {vm_inst.vm_host}",
                "command": f"ssh {vm_inst.vm_host} 'echo VM reachable'",
                "description": f"Verify SSH connectivity to VM host {vm_inst.vm_host}",
            })


class ProviderHealthCheck(HealthCheck):
    """Check provider configuration and API keys."""
    
    def check(self, diag: dict[str, Any], tool) -> None:
        """Check if provider is properly configured."""
        # This would be implemented with actual provider checking logic
        # For now, it's a placeholder that would check API keys, etc.
        pass


class HumanToolHealthCheck(HealthCheck):
    """Special health check for human tool category."""
    
    def check(self, diag: dict[str, Any], tool) -> None:
        """Handle human tool special case."""
        if tool.name == "human":
            diag["provider"] = "manual"
            diag["provider_configured"] = True
            diag["api_key_present"] = True
            diag["status"] = "available"
            return True
        return False


class HealthStatusCalculator:
    """Calculate overall health status from diagnostics."""
    
    @staticmethod
    def calculate_status(diag: dict[str, Any]) -> str:
        """Calculate overall health status."""
        if diag["name"] == "human":
            return "available"
        
        # Check for critical issues
        if diag["issues"]:
            has_critical = any(
                "not found" in issue.lower() or "not running" in issue.lower() 
                for issue in diag["issues"]
            )
            if has_critical:
                return "error"
        
        # Check if tool is available
        if diag["binary_found"] or diag["docker_instance"] or diag["kvm_instance"] or diag["vm_instance"]:
            return "healthy" if diag["provider_configured"] and diag["api_key_present"] else "warning"
        
        return "unavailable"


class HealthCheckerRefactored:
    """Main health checker that orchestrates specific checks."""
    
    def __init__(self):
        self.checks = [
            HumanToolHealthCheck(),
            BinaryHealthCheck(),
            InstanceHealthCheck(),
            ProviderHealthCheck(),
        ]
        self.status_calculator = HealthStatusCalculator()
    
    def create_base_diagnosis(self, tool, tool_providers: dict[str, str]) -> dict[str, Any]:
        """Create base diagnosis dictionary."""
        return {
            "name": tool.name,
            "category": tool.category.value,
            "available": tool.is_available,
            "binary": tool.binary,
            "binary_found": bool(tool.binary and shutil.which(tool.binary)),
            "provider": tool_providers.get(tool.name, "openrouter"),
            "provider_configured": False,
            "api_key_present": False,
            "docker_instance": False,
            "kvm_instance": False,
            "vm_instance": False,
            "status": "unknown",
            "issues": [],
            "fixes": [],
        }
    
    def apply_provider_health(self, diag: dict[str, Any], configured_providers: dict[str, Any]) -> None:
        """Apply provider-specific health information."""
        provider_name = diag["provider"]
        
        if diag["name"] == "human":
            # Already handled by HumanToolHealthCheck
            return
        
        if provider_name in configured_providers:
            diag["provider_configured"] = True
            diag["api_key_present"] = True
        else:
            diag["issues"].append(f"Provider '{provider_name}' not configured")
            diag["fixes"].append({
                "action": "configure_provider",
                "label": f"Configure {provider_name}",
                "command": f"# Add {provider_name} to your configuration",
                "description": f"Configure API keys for {provider_name}",
            })
    
    def check_tool_health(self, tool, tool_providers: dict[str, str], configured_providers: dict[str, Any]) -> dict[str, Any]:
        """Perform comprehensive health check for a tool."""
        # Create base diagnosis
        diag = self.create_base_diagnosis(tool, tool_providers)
        
        # Apply all health checks
        for health_check in self.checks:
            try:
                health_check.check(diag, tool)
                # If HumanToolHealthCheck handled it, we can stop
                if diag["name"] == "human" and diag["status"] == "available":
                    break
            except Exception as e:
                logger.error(f"Health check failed for {tool.name}", error=str(e))
                diag["issues"].append(f"Health check error: {str(e)}")
        
        # Apply provider health
        self.apply_provider_health(diag, configured_providers)
        
        # Calculate final status
        diag["status"] = self.status_calculator.calculate_status(diag)
        
        return diag
    
    def check_all_tools_health(self, tool_registry, configured_providers: dict[str, Any]) -> list[dict[str, Any]]:
        """Check health for all registered tools."""
        results = []
        tool_providers = self._get_tool_providers(tool_registry)
        
        for tool in tool_registry.list_tools():
            try:
                health = self.check_tool_health(tool, tool_providers, configured_providers)
                results.append(health)
            except Exception as e:
                logger.error(f"Failed to check health for {tool.name}", error=str(e))
                results.append({
                    "name": tool.name,
                    "status": "error",
                    "issues": [f"Health check failed: {str(e)}"],
                    "fixes": []
                })
        
        return results
    
    def _get_tool_providers(self, tool_registry) -> dict[str, str]:
        """Extract tool-to-provider mapping from registry."""
        # This would depend on the actual tool registry implementation
        return {}
