# src/processors/historical.py
"""
Procesador de datos históricos - MVP v1.0

Procesa mediciones históricas pendientes agrupándolas por períodos de 15 minutos
y generando un único registro estadístico por entrada y período.
"""

from datetime import datetime
import logging
from collections import defaultdict
from .base import BaseProcessor
from ..db.database import (
    get_unprocessed_measurements,
    mark_as_processed_batch,
    insert_registros_batch
)
from ..models.entrada import Entrada
from ..config.settings import BATCH_SIZE, PROCESS_INTERVAL

logger = logging.getLogger(__name__)

class HistoricalProcessor(BaseProcessor):
    
    def process_historical_data(self):
        """
        Procesa todos los datos históricos pendientes.
        """
        if not self.check_connection():
            return False

        logger.info("Iniciando procesamiento histórico...")
        try:
            # Obtenemos todas las mediciones no procesadas
            measurements = get_unprocessed_measurements(self.conn)
            if not measurements:
                logger.info("No hay datos históricos pendientes")
                return True

            # Agrupamos mediciones por período y entrada
            mediciones_por_periodo = {}  # {(periodo, id_entrada): {'mediciones': [], 'ids': [], 'dmac': dmac}}
            
            for m_id, dmac, temp, fecha, id_entrada in measurements:
                # Normalizar el período (redondear a 15 minutos)
                periodo = fecha.replace(
                    minute=(fecha.minute // PROCESS_INTERVAL) * PROCESS_INTERVAL,
                    second=0,
                    microsecond=0
                )
                
                key = (periodo, id_entrada)
                if key not in mediciones_por_periodo:
                    mediciones_por_periodo[key] = {
                        'mediciones': [],
                        'ids': [],
                        'dmac': dmac
                    }
                
                mediciones_por_periodo[key]['mediciones'].append((temp, fecha))
                mediciones_por_periodo[key]['ids'].append(m_id)

            # Procesar cada período completo
            registros_historicos = []
            all_processed_ids = []

            for (periodo, id_entrada), datos in mediciones_por_periodo.items():
                entrada = Entrada(id_entrada, datos['dmac'], periodo)
                
                # Procesar todas las mediciones del período
                for temp, fecha in datos['mediciones']:
                    entrada.agregar_medicion(temp, fecha)
                
                # Obtener estadísticas del período
                stats = entrada.get_estadisticas()
                if stats and stats['cantidad_mediciones'] > 0:
                    registros_historicos.append((
                        0, 
                        id_entrada, 
                        stats['periodo_fin'],  # Usar periodo_fin en lugar de periodo_inicio
                        stats['promedio'], 
                        stats['maximo'],
                        stats['minimo'], 
                        stats['desvio']
                    ))
                    all_processed_ids.extend(datos['ids'])

                    if self.verbose:
                        logger.debug(
                            f"Período {periodo}: Entrada {id_entrada} - "
                            f"Mediciones: {stats['cantidad_mediciones']}, "
                            f"Promedio: {stats['promedio']}, "
                            f"Min/Max: {stats['minimo']}/{stats['maximo']}"
                        )

            # Actualizar base de datos
            if all_processed_ids:
                mark_as_processed_batch(self.conn, all_processed_ids)
                
            if registros_historicos:
                insert_registros_batch(self.conn, registros_historicos)

            logger.info(f"Procesamiento histórico completado. Registros generados: {len(registros_historicos)}")
            return True

        except Exception as e:
            logger.error(f"Error en procesamiento histórico: {e}", exc_info=True)
            return False
    
    def _process_batch(self, measurements):
        """
        Procesa un lote de mediciones agrupándolas por período y entrada.
        """
        if not measurements:
            return []

        # Diccionario para mantener todas las mediciones por período y entrada
        # Estructura: {(periodo, entrada_id): {'dmac': dmac, 'mediciones': [(id, temp, fecha)]}}
        periodo_entrada_dict = {}
        pending_marks = set()  # Usamos set para evitar duplicados

        # Agrupar todas las mediciones por período y entrada
        for m_id, dmac, temp, fecha, id_entrada in measurements:
            if not all([dmac, id_entrada, temp is not None]):
                continue

            # Normalizar el período
            periodo = fecha.replace(
                minute=(fecha.minute // PROCESS_INTERVAL) * PROCESS_INTERVAL,
                second=0,
                microsecond=0
            )
            
            key = (periodo, id_entrada)
            if key not in periodo_entrada_dict:
                periodo_entrada_dict[key] = {
                    'dmac': dmac,
                    'mediciones': []
                }
            
            periodo_entrada_dict[key]['mediciones'].append((m_id, temp, fecha))
            pending_marks.add(m_id)

        # Procesar cada período y entrada una sola vez
        processed_data = []
        for (periodo, id_entrada), data in periodo_entrada_dict.items():
            entrada = Entrada(id_entrada, data['dmac'], periodo)
            
            # Procesar todas las mediciones de este período y entrada
            for _, temp, fecha in data['mediciones']:
                entrada.agregar_medicion(temp, fecha)

            # Generar un único registro estadístico
            stats = entrada.get_estadisticas()
            if stats and stats['cantidad_mediciones'] > 0:
                processed_data.append((
                    0,
                    id_entrada,
                    stats['periodo_inicio'],
                    stats['promedio'],
                    stats['maximo'],
                    stats['minimo'],
                    stats['desvio']
                ))
                
                if self.verbose:
                    logger.debug(
                        f"Generado registro único para entrada {id_entrada}, "
                        f"DMAC {data['dmac']}, período {periodo:%Y-%m-%d %H:%M} "
                        f"con {stats['cantidad_mediciones']} mediciones"
                    )

        # Actualizar base de datos
        if pending_marks:
            mark_as_processed_batch(self.conn, list(pending_marks))

        if processed_data:
            insert_registros_batch(self.conn, processed_data)

        return list(pending_marks)