"""Symptom Abstraction - Converts raw metrics into symptoms."""

import logging
from typing import Dict, List, Any, Literal


logger = logging.getLogger(__name__)


Severity = Literal["low", "medium", "high", "critical"]


class Symptom:
    """Represents a detected system symptom."""
    
    def __init__(
        self,
        symptom_type: str,
        severity: Severity,
        duration: str,
        impact: List[str],
        metadata: Dict[str, Any] = None
    ):
        self.type = symptom_type
        self.severity = severity
        self.duration = duration
        self.impact = impact
        self.metadata = metadata or {}
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert symptom to dictionary."""
        return {
            "type": self.type,
            "severity": self.severity,
            "duration": self.duration,
            "impact": self.impact,
            "metadata": self.metadata
        }


def detect_cpu_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect CPU-related symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of CPU symptoms.
    """
    symptoms = []
    cpu_data = telemetry.get("cpu", {})
    
    avg_cpu = cpu_data.get("average", 0)
    max_cpu = cpu_data.get("max", 0)
    
    if avg_cpu > 90:
        symptoms.append(Symptom(
            symptom_type="cpu_pressure",
            severity="critical",
            duration="current",
            impact=["severe system slowdown", "possible freezing"],
            metadata={"average_cpu": avg_cpu, "max_cpu": max_cpu}
        ))
    elif avg_cpu > 75:
        symptoms.append(Symptom(
            symptom_type="cpu_pressure",
            severity="high",
            duration="current",
            impact=["system slowdown", "reduced responsiveness"],
            metadata={"average_cpu": avg_cpu, "max_cpu": max_cpu}
        ))
    elif avg_cpu > 60:
        symptoms.append(Symptom(
            symptom_type="cpu_pressure",
            severity="medium",
            duration="current",
            impact=["mild slowdown"],
            metadata={"average_cpu": avg_cpu, "max_cpu": max_cpu}
        ))
    
    return symptoms


def detect_memory_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect memory-related symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of memory symptoms.
    """
    symptoms = []
    mem_data = telemetry.get("memory", {})
    
    mem_percent = mem_data.get("percent", 0)
    available_gb = mem_data.get("available_gb", 0)
    
    if mem_percent > 95:
        symptoms.append(Symptom(
            symptom_type="memory_pressure",
            severity="critical",
            duration="current",
            impact=["system instability", "possible crashes", "swapping"],
            metadata={"percent": mem_percent, "available_gb": available_gb}
        ))
    elif mem_percent > 85:
        symptoms.append(Symptom(
            symptom_type="memory_pressure",
            severity="high",
            duration="current",
            impact=["reduced performance", "increased swapping"],
            metadata={"percent": mem_percent, "available_gb": available_gb}
        ))
    elif mem_percent > 75:
        symptoms.append(Symptom(
            symptom_type="memory_pressure",
            severity="medium",
            duration="current",
            impact=["potential slowdown"],
            metadata={"percent": mem_percent, "available_gb": available_gb}
        ))
    
    return symptoms


def detect_disk_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect disk-related symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of disk symptoms.
    """
    symptoms = []
    disk_data = telemetry.get("disk", [])
    
    for disk in disk_data:
        percent_used = disk.get("percent", 0)
        free_gb = disk.get("free_gb", 0)
        mountpoint = disk.get("mountpoint", "unknown")
        
        if percent_used > 95:
            symptoms.append(Symptom(
                symptom_type="disk_space_critical",
                severity="critical",
                duration="current",
                impact=["cannot save files", "system may freeze", "application failures"],
                metadata={
                    "mountpoint": mountpoint,
                    "percent_used": percent_used,
                    "free_gb": free_gb
                }
            ))
        elif percent_used > 90:
            symptoms.append(Symptom(
                symptom_type="disk_space_low",
                severity="high",
                duration="current",
                impact=["limited storage", "potential write failures"],
                metadata={
                    "mountpoint": mountpoint,
                    "percent_used": percent_used,
                    "free_gb": free_gb
                }
            ))
        elif percent_used > 80:
            symptoms.append(Symptom(
                symptom_type="disk_space_warning",
                severity="medium",
                duration="current",
                impact=["approaching capacity"],
                metadata={
                    "mountpoint": mountpoint,
                    "percent_used": percent_used,
                    "free_gb": free_gb
                }
            ))
    
    return symptoms


def detect_battery_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect battery-related symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of battery symptoms.
    """
    symptoms = []
    battery_data = telemetry.get("battery")
    
    if battery_data is None:
        return symptoms
    
    battery_percent = battery_data.get("percent", 100)
    is_plugged = battery_data.get("plugged", True)
    
    if not is_plugged and battery_percent < 10:
        symptoms.append(Symptom(
            symptom_type="battery_critical",
            severity="critical",
            duration="current",
            impact=["imminent shutdown", "data loss risk"],
            metadata={"percent": battery_percent, "plugged": is_plugged}
        ))
    elif not is_plugged and battery_percent < 20:
        symptoms.append(Symptom(
            symptom_type="battery_low",
            severity="high",
            duration="current",
            impact=["limited runtime", "should plug in"],
            metadata={"percent": battery_percent, "plugged": is_plugged}
        ))
    
    return symptoms


def detect_network_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect network-related symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of network symptoms.
    """
    symptoms = []
    network_data = telemetry.get("extended_telemetry", {}).get("network", {})
    
    # DNS resolution failure
    if network_data.get("dns_resolution") is False:
        symptoms.append(Symptom(
            symptom_type="network_dns_failure",
            severity="high",
            duration="current",
            impact=["unable to resolve domain names", "network connectivity issues"],
            metadata={"dns_resolution": False}
        ))
    
    # Gateway unreachable
    if network_data.get("gateway_reachable") is False:
        symptoms.append(Symptom(
            symptom_type="network_gateway_unreachable",
            severity="high",
            duration="current",
            impact=["no internet connectivity", "network routing issues"],
            metadata={"gateway_reachable": False}
        ))
    
    # High latency
    latency = network_data.get("gateway_latency_ms")
    if latency and latency > 200:
        symptoms.append(Symptom(
            symptom_type="network_high_latency",
            severity="medium",
            duration="current",
            impact=["slow network response", "potential connectivity issues"],
            metadata={"latency_ms": latency}
        ))
    
    # Interfaces down
    interfaces_down = network_data.get("interfaces_down", [])
    if len(interfaces_down) > 0:
        symptoms.append(Symptom(
            symptom_type="network_interface_down",
            severity="medium",
            duration="current",
            impact=["network interface unavailable"],
            metadata={"interfaces": interfaces_down}
        ))
    
    return symptoms


def detect_application_crash_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect application crash symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of application crash symptoms.
    """
    symptoms = []
    crash_data = telemetry.get("extended_telemetry", {}).get("application_crashes", {})
    
    crash_count = crash_data.get("crash_count_24h", 0)
    
    if crash_count > 10:
        symptoms.append(Symptom(
            symptom_type="application_crashes_frequent",
            severity="high",
            duration="24 hours",
            impact=["system instability", "potential application issues"],
            metadata={"crash_count": crash_count}
        ))
    elif crash_count > 5:
        symptoms.append(Symptom(
            symptom_type="application_crashes_elevated",
            severity="medium",
            duration="24 hours",
            impact=["increased application failures"],
            metadata={"crash_count": crash_count}
        ))
    elif crash_count > 0:
        symptoms.append(Symptom(
            symptom_type="application_crashes_detected",
            severity="low",
            duration="24 hours",
            impact=["some application crashes observed"],
            metadata={"crash_count": crash_count}
        ))
    
    return symptoms


def detect_hardware_health_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect hardware health symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of hardware health symptoms.
    """
    symptoms = []
    hardware_data = telemetry.get("extended_telemetry", {}).get("hardware_health", {})
    
    # Disk I/O errors
    disk_io_errors = hardware_data.get("disk_io_errors", {})
    for disk, errors in disk_io_errors.items():
        read_errors = errors.get("read_errors", 0)
        write_errors = errors.get("write_errors", 0)
        total_errors = read_errors + write_errors
        
        if total_errors > 100:
            symptoms.append(Symptom(
                symptom_type="disk_io_errors_critical",
                severity="critical",
                duration="current",
                impact=["potential disk failure", "data integrity risk"],
                metadata={"disk": disk, "read_errors": read_errors, "write_errors": write_errors}
            ))
        elif total_errors > 10:
            symptoms.append(Symptom(
                symptom_type="disk_io_errors_elevated",
                severity="high",
                duration="current",
                impact=["disk reliability concerns"],
                metadata={"disk": disk, "read_errors": read_errors, "write_errors": write_errors}
            ))
    
    # High temperatures
    temperatures = hardware_data.get("temperatures", {})
    for sensor, temp in temperatures.items():
        if temp > 85:
            symptoms.append(Symptom(
                symptom_type="hardware_temperature_critical",
                severity="high",
                duration="current",
                impact=["thermal throttling", "potential hardware damage"],
                metadata={"sensor": sensor, "temperature": temp}
            ))
        elif temp > 75:
            symptoms.append(Symptom(
                symptom_type="hardware_temperature_elevated",
                severity="medium",
                duration="current",
                impact=["elevated operating temperature"],
                metadata={"sensor": sensor, "temperature": temp}
            ))
    
    return symptoms


def detect_driver_stability_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect driver stability symptoms from telemetry.
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of driver stability symptoms.
    """
    symptoms = []
    driver_data = telemetry.get("extended_telemetry", {}).get("driver_stability", {})
    
    driver_restarts = driver_data.get("driver_restarts", [])
    
    if len(driver_restarts) > 5:
        symptoms.append(Symptom(
            symptom_type="driver_instability_frequent",
            severity="high",
            duration="recent",
            impact=["system instability", "potential hardware issues"],
            metadata={"restart_count": len(driver_restarts)}
        ))
    elif len(driver_restarts) > 0:
        symptoms.append(Symptom(
            symptom_type="driver_instability_detected",
            severity="medium",
            duration="recent",
            impact=["driver stability concerns"],
            metadata={"restart_count": len(driver_restarts)}
        ))
    
    return symptoms


def detect_security_posture_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Detect security posture symptoms from telemetry (observational only).
    
    Args:
        telemetry: Telemetry data dictionary.
        
    Returns:
        List of security posture symptoms.
    """
    symptoms = []
    security_data = telemetry.get("extended_telemetry", {}).get("security_posture", {})
    
    # Firewall disabled
    if security_data.get("firewall_enabled") is False:
        symptoms.append(Symptom(
            symptom_type="security_firewall_disabled",
            severity="medium",
            duration="current",
            impact=["reduced network protection"],
            metadata={"firewall_enabled": False}
        ))
    
    # Disk encryption disabled (if detectable)
    if security_data.get("disk_encryption") is False:
        symptoms.append(Symptom(
            symptom_type="security_encryption_disabled",
            severity="low",
            duration="current",
            impact=["data at rest not encrypted"],
            metadata={"disk_encryption": False}
        ))
    
    # OS updates pending
    if security_data.get("os_updates") == "pending":
        symptoms.append(Symptom(
            symptom_type="security_updates_pending",
            severity="low",
            duration="current",
            impact=["system updates available"],
            metadata={"os_updates": "pending"}
        ))
    
    return symptoms


def extract_all_symptoms(telemetry: Dict[str, Any]) -> List[Symptom]:
    """
    Extract all symptoms from telemetry data.
    
    Args:
        telemetry: Complete telemetry data dictionary.
        
    Returns:
        List of all detected symptoms.
    """
    symptoms = []
    
    # Core symptoms
    symptoms.extend(detect_cpu_symptoms(telemetry))
    symptoms.extend(detect_memory_symptoms(telemetry))
    symptoms.extend(detect_disk_symptoms(telemetry))
    symptoms.extend(detect_battery_symptoms(telemetry))
    
    # Extended symptoms
    symptoms.extend(detect_network_symptoms(telemetry))
    symptoms.extend(detect_application_crash_symptoms(telemetry))
    symptoms.extend(detect_hardware_health_symptoms(telemetry))
    symptoms.extend(detect_driver_stability_symptoms(telemetry))
    symptoms.extend(detect_security_posture_symptoms(telemetry))
    
    logger.info(f"Extracted {len(symptoms)} symptoms from telemetry")
    return symptoms
