"""
Módulo de Base de Datos - MVP v1.0

Maneja conexiones y operaciones de base de datos
"""

import logging
import mysql.connector
from mysql.connector import Error, pooling
from ..config.settings import DB_CONFIG
from datetime import datetime

logger = logging.getLogger(__name__)

# Pool de conexiones para cada base de datos
connection_pools = {}

def get_connection_pool(db_name: str):
    """
    Obtiene o crea un pool de conexiones para una base de datos
    
    Args:
        db_name: Nombre de la base de datos
        
    Returns:
        MySQLConnectionPool: Pool de conexiones
    """
    if db_name not in connection_pools:
        try:
            pool_config = {
                'pool_name': f"pool_{db_name}",
                'pool_size': 5,
                'host': DB_CONFIG['host'],
                'port': DB_CONFIG['port'],
                'user': DB_CONFIG['user'],
                'password': DB_CONFIG['password'],
                'database': db_name
            }
            connection_pools[db_name] = mysql.connector.pooling.MySQLConnectionPool(**pool_config)
            logger.info(f"Pool de conexiones creado para {db_name}")
        except Error as e:
            logger.error(f"Error creando pool de conexiones: {e}")
            return None
    
    return connection_pools[db_name]

def connect(db_name: str):
    """
    Obtiene una conexión del pool
    
    Args:
        db_name: Nombre de la base de datos
        
    Returns:
        MySQLConnection: Conexión a la base de datos
    """
    pool = get_connection_pool(db_name)
    if pool:
        try:
            return pool.get_connection()
        except Error as e:
            logger.error(f"Error obteniendo conexión del pool: {e}")
    return None

def execute_query(connection, query: str, params=None, commit=False):
    """
    Ejecuta una query con manejo de errores
    
    Args:
        connection: Conexión a la base de datos
        query: Query SQL
        params: Parámetros para la query
        commit: Si se debe hacer commit
        
    Returns:
        tuple: (success, result/error_message)
    """
    cursor = None
    try:
        cursor = connection.cursor(dictionary=True)
        cursor.execute(query, params or ())
        
        if commit:
            connection.commit()
            return True, cursor.rowcount
        else:
            return True, cursor.fetchall()

    except Error as e:
        logger.error(f"Error ejecutando query: {e}")
        if connection and commit:
            connection.rollback()
        return False, str(e)

    finally:
        if cursor:
            cursor.close()

def execute_many(connection, query: str, params_list: list):
    """
    Ejecuta una query múltiple veces con diferentes parámetros
    
    Args:
        connection: Conexión a la base de datos
        query: Query SQL
        params_list: Lista de parámetros
        
    Returns:
        tuple: (success, rowcount/error_message)
    """
    cursor = None
    try:
        cursor = connection.cursor()
        cursor.executemany(query, params_list)
        connection.commit()
        return True, cursor.rowcount

    except Error as e:
        logger.error(f"Error en executemany: {e}")
        if connection:
            connection.rollback()
        return False, str(e)

    finally:
        if cursor:
            cursor.close()

def close_all_pools():
    """Cierra todos los pools de conexiones"""
    for db_name, pool in connection_pools.items():
        try:
            pool.close()
            logger.info(f"Pool cerrado para {db_name}")
        except Error as e:
            logger.error(f"Error cerrando pool {db_name}: {e}")
    
    connection_pools.clear()
    
    
###################################################################
###  realtime
###################################################################

def get_unprocessed_measurements(conn, debug=False):
    """
    Obtiene mediciones no procesadas de la tabla bandeja_blue
    
    Returns:
        list: [(id, dmac, temp, fecha, id_entrada), ...]
    """
    try:
        cursor = conn.cursor()
        query = """
            SELECT 
                bb.id,
                bb.dmac,
                bb.temp,
                bb.fecha,
                e.idEntrada
            FROM bandeja_blue bb
            JOIN modbus m ON bb.dmac = m.dmac
            JOIN entradas e ON m.idModbus = e.idModbus
            WHERE bb.procesado_el IS NULL
            ORDER BY bb.fecha
            LIMIT 1000
        """
        cursor.execute(query)
        measurements = cursor.fetchall()
        
        if debug:
            logger.debug(f"Obtenidas {len(measurements)} mediciones sin procesar")
            
        return measurements
        
    except Error as e:
        logger.error(f"Error obteniendo mediciones sin procesar: {e}")
        return []
    finally:
        if 'cursor' in locals():
            cursor.close()

def get_active_sensors(conn):
    """
    Obtiene lista de sensores activos
    
    Returns:
        list: [(sensor_id, dmac, id_entrada), ...]
    """
    try:
        cursor = conn.cursor()
        query = """
            SELECT 
                m.idModbus,
                m.dmac,
                e.idEntrada
            FROM modbus m
            JOIN entradas e ON m.idModbus = e.idModbus
            WHERE m.estado = 1
        """
        cursor.execute(query)
        return cursor.fetchall()
        
    except Error as e:
        logger.error(f"Error obteniendo sensores activos: {e}")
        return []
    finally:
        if 'cursor' in locals():
            cursor.close()

def mark_as_processed_batch(conn, ids, debug=False):
    """
    Marca un lote de mediciones como procesadas
    
    Args:
        ids (list): Lista de IDs de mediciones
    """
    if not ids:
        return
        
    try:
        cursor = conn.cursor()
        placeholders = ','.join(['%s'] * len(ids))
        query = f"""
            UPDATE bandeja_blue 
            SET procesado_el = %s
            WHERE id IN ({placeholders})
        """
        params = [datetime.now()] + ids
        
        cursor.execute(query, params)
        conn.commit()
        
        if debug:
            logger.debug(f"Marcadas {len(ids)} mediciones como procesadas")
            
    except Error as e:
        conn.rollback()
        logger.error(f"Error marcando mediciones como procesadas: {e}")
    finally:
        if 'cursor' in locals():
            cursor.close()

def insert_registros_batch(conn, registros, debug=False):
    """
    Inserta un lote de registros estadísticos
    
    Args:
        registros (list): Lista de tuplas (idSistema, idEntrada, fecha, medio, maximo, minimo, desvio)
    """
    if not registros:
        return
        
    try:
        cursor = conn.cursor()
        query = """
            INSERT IGNORE INTO registros 
                (idSistema, idEntrada, fecha, medio, maximo, minimo, desvio)
            VALUES 
                (%s, %s, %s, %s, %s, %s, %s)
        """
        cursor.executemany(query, registros)
        conn.commit()
        
        if debug:
            logger.debug(f"Insertados {len(registros)} registros estadísticos")
            
    except Error as e:
        conn.rollback()
        logger.error(f"Error insertando registros: {e}")
    finally:
        if 'cursor' in locals():
            cursor.close()