"""Diagnostic Rules Engine - Deterministic rule-based diagnostics."""

import logging
from typing import Dict, List, Any, Literal
from doctor.diagnostics.symptoms import Symptom, Severity


logger = logging.getLogger(__name__)


Urgency = Literal["high", "medium", "low"]


class DiagnosticRule:
    """Represents a diagnostic rule."""
    
    def __init__(
        self,
        name: str,
        condition: callable,
        urgency: Urgency,
        category: str
    ):
        self.name = name
        self.condition = condition
        self.urgency = urgency
        self.category = category
    
    def evaluate(self, symptoms: List[Symptom], telemetry: Dict[str, Any]) -> bool:
        """
        Evaluate if this rule matches the current state.
        
        Args:
            symptoms: List of detected symptoms.
            telemetry: Raw telemetry data.
            
        Returns:
            True if rule matches, False otherwise.
        """
        try:
            return self.condition(symptoms, telemetry)
        except Exception as e:
            logger.warning(f"Rule '{self.name}' evaluation failed: {e}")
            return False


# Rule definitions
RULES = [
    DiagnosticRule(
        name="High CPU Pressure",
        condition=lambda s, t: any(
            sym.type == "cpu_pressure" and sym.severity in ["high", "critical"]
            for sym in s
        ),
        urgency="high",
        category="performance"
    ),
    DiagnosticRule(
        name="Critical Memory Pressure",
        condition=lambda s, t: any(
            sym.type == "memory_pressure" and sym.severity == "critical"
            for sym in s
        ),
        urgency="high",
        category="performance"
    ),
    DiagnosticRule(
        name="Critical Disk Space",
        condition=lambda s, t: any(
            sym.type == "disk_space_critical"
            for sym in s
        ),
        urgency="high",
        category="storage"
    ),
    DiagnosticRule(
        name="Low Disk Space",
        condition=lambda s, t: any(
            sym.type == "disk_space_low"
            for sym in s
        ),
        urgency="medium",
        category="storage"
    ),
    DiagnosticRule(
        name="Critical Battery",
        condition=lambda s, t: any(
            sym.type == "battery_critical"
            for sym in s
        ),
        urgency="high",
        category="power"
    ),
    DiagnosticRule(
        name="Low Battery",
        condition=lambda s, t: any(
            sym.type == "battery_low"
            for sym in s
        ),
        urgency="medium",
        category="power"
    ),
    DiagnosticRule(
        name="Medium CPU Pressure",
        condition=lambda s, t: any(
            sym.type == "cpu_pressure" and sym.severity == "medium"
            for sym in s
        ),
        urgency="medium",
        category="performance"
    ),
    DiagnosticRule(
        name="Medium Memory Pressure",
        condition=lambda s, t: any(
            sym.type == "memory_pressure" and sym.severity == "medium"
            for sym in s
        ),
        urgency="medium",
        category="performance"
    ),
    DiagnosticRule(
        name="Network Connectivity Issues",
        condition=lambda s, t: any(
            sym.type in ["network_dns_failure", "network_gateway_unreachable", "network_interface_down"]
            for sym in s
        ),
        urgency="high",
        category="network"
    ),
    DiagnosticRule(
        name="Frequent Application Crashes",
        condition=lambda s, t: any(
            sym.type == "application_crashes_frequent"
            for sym in s
        ),
        urgency="high",
        category="stability"
    ),
    DiagnosticRule(
        name="Critical Disk I/O Errors",
        condition=lambda s, t: any(
            sym.type == "disk_io_errors_critical"
            for sym in s
        ),
        urgency="high",
        category="hardware"
    ),
    DiagnosticRule(
        name="Critical Hardware Temperature",
        condition=lambda s, t: any(
            sym.type == "hardware_temperature_critical"
            for sym in s
        ),
        urgency="high",
        category="hardware"
    ),
    DiagnosticRule(
        name="Driver Instability",
        condition=lambda s, t: any(
            sym.type == "driver_instability_frequent"
            for sym in s
        ),
        urgency="high",
        category="stability"
    ),
    DiagnosticRule(
        name="Security Posture Concerns",
        condition=lambda s, t: any(
            sym.type in ["security_firewall_disabled", "security_encryption_disabled"]
            for sym in s
        ),
        urgency="medium",
        category="security"
    ),
]


def evaluate_rules(symptoms: List[Symptom], telemetry: Dict[str, Any]) -> List[DiagnosticRule]:
    """
    Evaluate all diagnostic rules against current state.
    
    Args:
        symptoms: List of detected symptoms.
        telemetry: Raw telemetry data.
        
    Returns:
        List of matching rules.
    """
    matching_rules = []
    
    for rule in RULES:
        if rule.evaluate(symptoms, telemetry):
            matching_rules.append(rule)
            logger.debug(f"Rule matched: {rule.name}")
    
    logger.info(f"Matched {len(matching_rules)} diagnostic rules")
    return matching_rules


def get_rule_by_name(name: str) -> DiagnosticRule:
    """
    Get a rule by its name.
    
    Args:
        name: Rule name.
        
    Returns:
        DiagnosticRule instance or None if not found.
    """
    for rule in RULES:
        if rule.name == name:
            return rule
    return None
