"""
Plugin pour LibreHardwareMonitor
Utilise l'API REST intégrée de LHM (port 8085 par défaut)
"""
import requests
from typing import Dict, List, Optional, Any
from .base import BasePlugin


class LibreHardwareMonitorPlugin(BasePlugin):
    """Plugin pour LibreHardwareMonitor"""
    
    def __init__(self, config: dict):
        super().__init__(config)
        self.history = {}
        self.max_history = 120  # 2 minutes à 1 sample/sec
    
    def get_id(self) -> str:
        return 'librehardwaremonitor'
    
    def get_name(self) -> str:
        return 'LibreHardwareMonitor'
    
    def get_default_port(self) -> int:
        return 8085
    
    def test_connection(self) -> Dict[str, Any]:
        """Teste la connexion à LibreHardwareMonitor"""
        try:
            url = f"{self.get_base_url()}/data.json"
            response = requests.get(url, timeout=5)
            response.raise_for_status()
            
            data = response.json()
            
            # Extraire la version si disponible
            version = "Inconnue"
            if data and "Text" in data:
                version = data.get("Text", "LibreHardwareMonitor")
            
            # Compter les capteurs
            sensors = self.parse_sensors(data)
            
            return {
                'success': True,
                'message': f'Connecté - {len(sensors)} capteurs détectés',
                'version': version,
                'sensor_count': len(sensors)
            }
            
        except requests.exceptions.ConnectionError:
            return {
                'success': False,
                'message': f'Impossible de se connecter à {self.get_base_url()}. Vérifiez que LibreHardwareMonitor est lancé avec le serveur web activé.'
            }
        except requests.exceptions.Timeout:
            return {
                'success': False,
                'message': 'Timeout - Le serveur ne répond pas'
            }
        except Exception as e:
            return {
                'success': False,
                'message': f'Erreur: {str(e)}'
            }
    
    def get_data(self) -> Optional[Dict]:
        """Récupère les données JSON depuis LHM Remote Server"""
        try:
            url = f"{self.get_base_url()}/data.json"
            response = requests.get(url, timeout=5)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"Erreur LHM get_data: {e}")
            return None
    
    def get_hierarchy(self) -> List[dict]:
        """Récupère la hiérarchie des capteurs pour l'admin"""
        data = self.get_data()
        if not data:
            return []
        
        return self._build_hierarchy(data)
    
    def _build_hierarchy(self, data: Dict) -> List[dict]:
        """Construit la hiérarchie des capteurs"""
        if not data or "Children" not in data:
            return []
        
        def build_tree(node, level=0):
            node_text = node.get("Text", "")
            node_value = node.get("Value", "")
            sensor_id = node.get("SensorId", "")
            
            result = {
                "name": node_text,
                "value": node_value,
                "id": sensor_id,
                "level": level,
                "type": self._guess_sensor_type(node_text, node_value) if node_value else "group",
                "children": []
            }
            
            if "Children" in node and node["Children"]:
                for child in node["Children"]:
                    result["children"].append(build_tree(child, level + 1))
            
            return result
        
        tree = []
        for child in data.get("Children", []):
            tree.append(build_tree(child))
        
        return tree
    
    def parse_sensors(self, data: Dict) -> List[Dict]:
        """Parse les données et retourne une liste plate de capteurs"""
        sensors = []
        
        if not data or "Children" not in data:
            return sensors
        
        def extract_sensors(node, parent_name="", hardware_name="", hardware_type=""):
            node_text = node.get("Text", "")
            current_path = f"{parent_name}/{node_text}" if parent_name else node_text
            
            # Détecter le type de hardware au niveau 1
            if not hardware_name and "Children" in node:
                hw_type = self._guess_hardware_type(node_text)
                hardware_name = node_text
                hardware_type = hw_type
            
            # Si le nœud a une valeur, c'est un capteur
            if "Value" in node and node["Value"]:
                sensor_id = node.get("SensorId", "")
                if not sensor_id:
                    sensor_id = f"{current_path}".replace(" ", "-").lower()
                
                value_str = node.get("Value", "")
                raw_value = self._extract_numeric_value(value_str)
                unit = self._extract_unit(value_str)
                sensor_type = self._guess_sensor_type(node_text, value_str)
                
                sensor = {
                    "id": sensor_id,
                    "name": node_text,
                    "value": value_str,
                    "raw_value": raw_value,
                    "type": sensor_type,
                    "unit": unit,
                    "hardware": hardware_name,
                    "hardware_type": hardware_type,
                    "category": parent_name.split("/")[0] if "/" in parent_name else parent_name,
                    "path": current_path,
                    "min": node.get("Min", ""),
                    "max": node.get("Max", ""),
                }
                sensors.append(sensor)
            
            # Parcourir les enfants récursivement
            if "Children" in node:
                for child in node["Children"]:
                    extract_sensors(child, current_path, hardware_name, hardware_type)
        
        for child in data.get("Children", []):
            extract_sensors(child)
        
        return sensors
    
    def _guess_hardware_type(self, name: str) -> str:
        """Devine le type de hardware basé sur le nom"""
        name_lower = name.lower()
        
        if 'cpu' in name_lower or 'processor' in name_lower:
            return 'CPU'
        elif 'gpu' in name_lower or 'graphics' in name_lower or 'nvidia' in name_lower or 'amd' in name_lower or 'radeon' in name_lower or 'geforce' in name_lower:
            return 'GPU'
        elif 'memory' in name_lower or 'ram' in name_lower:
            return 'RAM'
        elif 'motherboard' in name_lower or 'mainboard' in name_lower:
            return 'Motherboard'
        elif 'storage' in name_lower or 'disk' in name_lower or 'ssd' in name_lower or 'hdd' in name_lower or 'nvme' in name_lower:
            return 'Storage'
        elif 'network' in name_lower or 'ethernet' in name_lower or 'wifi' in name_lower:
            return 'Network'
        elif 'battery' in name_lower:
            return 'Battery'
        else:
            return 'Other'
    
    def _guess_sensor_type(self, name: str, value: str) -> str:
        """Devine le type de capteur basé sur le nom et la valeur"""
        name_lower = name.lower()
        value_lower = value.lower()
        
        if "°c" in value_lower or "temperature" in name_lower or "temp" in name_lower:
            return "temperature"
        elif "%" in value or "load" in name_lower or "usage" in name_lower:
            return "percentage"
        elif "rpm" in value_lower or "fan" in name_lower:
            return "fan"
        elif "mhz" in value_lower or "ghz" in value_lower or "clock" in name_lower:
            return "frequency"
        elif "w" in value_lower and "wh" not in value_lower:
            return "power"
        elif "v" in value_lower:
            return "voltage"
        elif "gb" in value_lower or "mb" in value_lower or "memory" in name_lower:
            return "memory"
        else:
            return "generic"
    
    def _extract_numeric_value(self, value_str: str) -> float:
        """Extrait la valeur numérique d'une chaîne"""
        try:
            # Enlever tous les caractères non numériques sauf le point et la virgule
            clean = value_str.replace("°C", "").replace("%", "").replace("V", "").replace("W", "")
            clean = clean.replace("MHz", "").replace("GHz", "").replace("GB", "").replace("MB", "")
            clean = clean.replace("RPM", "").replace(" ", "").replace(",", ".").strip()
            
            if clean:
                return float(clean)
        except (ValueError, AttributeError):
            pass
        return 0.0
    
    def _extract_unit(self, value_str: str) -> str:
        """Extrait l'unité d'une valeur"""
        value_str = value_str.strip()
        
        units = ['°C', '°F', '%', 'MHz', 'GHz', 'GB', 'MB', 'KB', 'RPM', 'W', 'V', 'A', 'GB/s', 'MB/s']
        for unit in units:
            if unit in value_str:
                return unit
        return ''
    
    # === Gestion de l'historique ===
    
    def update_history(self, sensors: List[Dict]):
        """Met à jour l'historique des capteurs pour les graphiques"""
        for sensor in sensors:
            sensor_id = sensor.get("id", "")
            if not sensor_id:
                continue
            
            raw_value = sensor.get("raw_value")
            if raw_value is None:
                raw_value = self._extract_numeric_value(sensor.get("value", ""))
            
            if raw_value == 0.0 and "0" not in sensor.get("value", ""):
                continue
            
            if sensor_id not in self.history:
                self.history[sensor_id] = []
            
            self.history[sensor_id].append(raw_value)
            
            if len(self.history[sensor_id]) > self.max_history:
                self.history[sensor_id] = self.history[sensor_id][-self.max_history:]
    
    def get_history(self, sensor_id: str, count: int = 60) -> List[float]:
        """Récupère l'historique d'un capteur"""
        if sensor_id not in self.history:
            return []
        return self.history[sensor_id][-count:]
