"""
Analizador de Desvíos - MVP v1.0

Implementa la lógica de detección y gestión de desvíos
de valores fuera de rango.
"""

import logging
from datetime import datetime
from collections import defaultdict
from ...config.constants import (
    STATE_NORMAL,
    STATE_ABOVE_MAX,
    STATE_ALARM_MAX,
    STATE_BELOW_MIN,
    STATE_ALARM_MIN
)

logger = logging.getLogger(__name__)

class DeviationAnalyzer:
    def __init__(self):
        self.configs = {}  # {(idSistema, idEntrada): config}
        self.states = defaultdict(self._create_default_state)
        self.debug = False
        self.alarm_batch = []
        self.metrics = {
            'current_states': defaultdict(int),
            'total_deviations': 0,
            'total_alarms': 0
        }

    def _create_default_state(self):
        """Crea un estado por defecto para una entrada"""
        return {
            'state_id': STATE_NORMAL,
            'start_time': None,
            'last_value': None
        }

    def update_configurations(self, conn):
        """Actualiza las configuraciones desde la base de datos"""
        try:
            cursor = conn.cursor(dictionary=True)
            cursor.execute("""
                SELECT 
                    idSistema, idEntrada, 
                    vMin1, vMax1, tMax1, 
                    generaAlarma
                FROM configuraciones
                WHERE generaAlarma = 1
            """)
            
            new_configs = {}
            for config in cursor.fetchall():
                key = (config['idSistema'], config['idEntrada'])
                new_configs[key] = config

            self.configs = new_configs
            if self.debug:
                logger.debug(f"Configuraciones actualizadas: {len(self.configs)} entradas")

        except Exception as e:
            logger.error(f"Error actualizando configuraciones: {str(e)}")
        finally:
            if 'cursor' in locals():
                cursor.close()

    def analyze(self, id_sistema, id_entrada, valor, fecha):
        """
        Analiza una medición para detectar desvíos
        
        Args:
            id_sistema (int): ID del sistema
            id_entrada (int): ID de la entrada
            valor (float): Valor medido
            fecha (datetime): Timestamp de la medición
            
        Returns:
            dict: Resultado del análisis
        """
        result = {
            'deviation_detected': False,
            'alarm_generated': False,
            'state_changed': False
        }

        key = (id_sistema, id_entrada)
        if key not in self.configs:
            return result

        config = self.configs[key]
        state = self.states[key]

        if self.debug:
            logger.debug(
                f"Analizando - Sistema: {id_sistema}, Entrada: {id_entrada}, "
                f"Valor: {valor}, Estado actual: {state['state_id']}"
            )

        # Verificar límites
        if valor > config['vMax1']:
            result.update(
                self._handle_high_value(key, valor, config, fecha)
            )
        elif valor < config['vMin1']:
            result.update(
                self._handle_low_value(key, valor, config, fecha)
            )
        else:
            if state['state_id'] != STATE_NORMAL:
                self._reset_state(key)
                result['state_changed'] = True

        # Actualizar métricas
        self.metrics['current_states'][state['state_id']] += 1
        
        return result

    def _handle_high_value(self, key, valor, config, fecha):
        """Maneja un valor que supera el máximo"""
        state = self.states[key]
        result = {'deviation_detected': True, 'alarm_generated': False}

        if state['state_id'] == STATE_NORMAL:
            state['state_id'] = STATE_ABOVE_MAX
            state['start_time'] = fecha
            state['last_value'] = valor
            result['state_changed'] = True
            self.metrics['total_deviations'] += 1

            if self.debug:
                logger.debug(f"Entrada {key} cambió a estado ABOVE_MAX")

        elif state['state_id'] == STATE_ABOVE_MAX:
            time_in_state = (fecha - state['start_time']).total_seconds()
            
            if self.debug:
                logger.debug(
                    f"Entrada {key} en ABOVE_MAX por {time_in_state} segundos "
                    f"(máximo: {config['tMax1']})"
                )

            if time_in_state >= config['tMax1']:
                self._add_alarm(key[0], key[1], valor, STATE_ALARM_MAX, fecha)
                state['state_id'] = STATE_ALARM_MAX
                result['alarm_generated'] = True
                result['state_changed'] = True
                self.metrics['total_alarms'] += 1

        return result

    def _handle_low_value(self, key, valor, config, fecha):
        """Maneja un valor por debajo del mínimo"""
        state = self.states[key]
        result = {'deviation_detected': True, 'alarm_generated': False}

        if state['state_id'] == STATE_NORMAL:
            state['state_id'] = STATE_BELOW_MIN
            state['start_time'] = fecha
            state['last_value'] = valor
            result['state_changed'] = True
            self.metrics['total_deviations'] += 1

            if self.debug:
                logger.debug(f"Entrada {key} cambió a estado BELOW_MIN")

        elif state['state_id'] == STATE_BELOW_MIN:
            time_in_state = (fecha - state['start_time']).total_seconds()
            
            if self.debug:
                logger.debug(
                    f"Entrada {key} en BELOW_MIN por {time_in_state} segundos "
                    f"(máximo: {config['tMax1']})"
                )

            if time_in_state >= config['tMax1']:
                self._add_alarm(key[0], key[1], valor, STATE_ALARM_MIN, fecha)
                state['state_id'] = STATE_ALARM_MIN
                result['alarm_generated'] = True
                result['state_changed'] = True
                self.metrics['total_alarms'] += 1

        return result

    def _reset_state(self, key):
        """Resetea el estado a normal"""
        if self.debug:
            logger.debug(f"Reseteando estado de entrada {key}")
        
        self.states[key] = self._create_default_state()

    def _add_alarm(self, id_sistema, id_entrada, valor, id_estado, fecha):
        """Agrega una alarma al lote pendiente"""
        if self.debug:
            logger.debug(
                f"Nueva alarma - Sistema: {id_sistema}, "
                f"Entrada: {id_entrada}, Estado: {id_estado}"
            )

        self.alarm_batch.append({
            'idSistema': id_sistema,
            'idEntrada': id_entrada,
            'valor': valor,
            'idEstado': id_estado,
            'fecha': fecha,
            'activa': 1
        })

    def get_metrics(self):
        """Obtiene métricas del analizador"""
        metrics = {
            'states': {
                'normal': self.metrics['current_states'][STATE_NORMAL],
                'above_max': self.metrics['current_states'][STATE_ABOVE_MAX],
                'alarm_max': self.metrics['current_states'][STATE_ALARM_MAX],
                'below_min': self.metrics['current_states'][STATE_BELOW_MIN],
                'alarm_min': self.metrics['current_states'][STATE_ALARM_MIN]
            },
            'total_deviations': self.metrics['total_deviations'],
            'total_alarms': self.metrics['total_alarms'],
            'pending_alarms': len(self.alarm_batch)
        }
        return metrics