"""
Calculador de Integraciones - MVP v1.0

Implementa los cálculos estadísticos para períodos de integración:
- Promedio
- Máximo
- Mínimo
- Desvío estándar
"""

import math
import logging
from datetime import datetime
from typing import List, Dict, Any

logger = logging.getLogger(__name__)

class IntegrationCalculator:
    def calculate_statistics(self, measurements: List[Dict[str, Any]]) -> Dict[str, float]:
        """
        Calcula estadísticas para un grupo de mediciones.
        
        Args:
            measurements: Lista de mediciones con al menos temp y fecha
            
        Returns:
            dict: Estadísticas calculadas o None si no hay suficientes datos
        """
        if not measurements:
            return None

        # Extraer los valores de temperatura
        valores = [m['temp'] for m in measurements]
        n = len(valores)
        
        if n == 0:
            return None

        # Cálculos básicos
        valor_sum = sum(valores)
        promedio = valor_sum / n
        maximo = max(valores)
        minimo = min(valores)

        # Cálculo de desvío estándar
        if n > 1:
            suma_cuadrados = sum((x - promedio) ** 2 for x in valores)
            desvio = math.sqrt(suma_cuadrados / (n - 1))
        else:
            desvio = 0.0

        return {
            'promedio': self._round(promedio),
            'maximo': self._round(maximo),
            'minimo': self._round(minimo),
            'desvio': self._round(desvio, 2),
            'cantidad_mediciones': n
        }

    def _round(self, value: float, decimals: int = 1) -> float:
        """
        Redondea un valor al número especificado de decimales
        
        Args:
            value: Valor a redondear
            decimals: Cantidad de decimales (default 1)
            
        Returns:
            float: Valor redondeado
        """
        try:
            return round(float(value), decimals)
        except (TypeError, ValueError) as e:
            logger.error(f"Error redondeando valor {value}: {str(e)}")
            return 0.0

    def weighted_average(self, measurements: List[Dict[str, Any]]) -> float:
        """
        Calcula el promedio ponderado por tiempo entre mediciones
        
        Args:
            measurements: Lista de mediciones ordenadas por fecha
            
        Returns:
            float: Promedio ponderado o None si no hay suficientes datos
        """
        if not measurements or len(measurements) < 2:
            return None

        # Ordenar por fecha
        sorted_measurements = sorted(measurements, key=lambda x: x['fecha'])
        
        total_weight = 0.0
        weighted_sum = 0.0
        prev_measurement = sorted_measurements[0]

        for measurement in sorted_measurements[1:]:
            # Calcular peso (tiempo entre mediciones)
            time_diff = (measurement['fecha'] - prev_measurement['fecha']).total_seconds()
            if time_diff <= 0:
                continue

            # Acumular suma ponderada
            weighted_sum += prev_measurement['temp'] * time_diff
            total_weight += time_diff
            prev_measurement = measurement

        if total_weight > 0:
            return self._round(weighted_sum / total_weight)
        
        return None

    def calculate_period_overlap(self, measurement_date: datetime, period_start: datetime, period_end: datetime) -> float:
        """
        Calcula el porcentaje de una medición que pertenece a un período
        
        Args:
            measurement_date: Fecha de la medición
            period_start: Inicio del período
            period_end: Fin del período
            
        Returns:
            float: Porcentaje de pertenencia al período (0.0 - 1.0)
        """
        if measurement_date < period_start or measurement_date >= period_end:
            return 0.0

        return 1.0

    def validate_measurements(self, measurements: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Filtra y valida mediciones
        
        Args:
            measurements: Lista de mediciones a validar
            
        Returns:
            List: Mediciones validadas
        """
        valid_measurements = []

        for measurement in measurements:
            # Validar que tenga los campos necesarios
            if not all(k in measurement for k in ['temp', 'fecha']):
                continue

            # Validar tipo de datos
            try:
                temp = float(measurement['temp'])
                if not isinstance(measurement['fecha'], datetime):
                    continue
            except (TypeError, ValueError):
                continue

            # Validar rango de temperatura (si es necesario)
            # TODO: Agregar validación de rango según configuración

            valid_measurements.append(measurement)

        return valid_measurements