"""
Configuration management for sensor data processing.

Handles loading and managing installation parameters and calibration data.
"""

import logging
from typing import Dict, Any, List, Tuple, Optional
from dataclasses import dataclass
import numpy as np
from .database import DatabaseConnection

logger = logging.getLogger(__name__)


@dataclass
class InstallationParameters:
    """
    Installation parameters for sensor processing.

    Converts data from MATLAB Parametri_Installazione function.
    """
    n_data_average: int  # Number of data points for averaging (NdatiMedia)
    n_data_despike: int  # Number of data points for despiking (Ndatidespike)
    mems_type: int  # Type of MEMS sensor (1, 2, etc.)
    acceleration_tolerance: float  # Tolerance for acceleration (tolleranzaAcc)
    installation_position: int  # Installation position code (pos_inst)
    temp_max: float  # Maximum valid temperature (Tmax)
    temp_min: float  # Minimum valid temperature (Tmin)
    single_event_level: float  # Single event alarm level (SEL)
    multiple_event_level: float  # Multiple event alarm level (MEL)


def load_installation_parameters(
    id_tool: int,
    conn: DatabaseConnection,
    has_rsn: bool = False,
    has_rsn_hr: bool = False,
    has_debris: bool = False
) -> InstallationParameters:
    """
    Load installation parameters from database.

    Converts MATLAB Parametri_Installazione.m function.

    Args:
        id_tool: Tool identifier
        conn: Database connection
        has_rsn: Whether installation has RSN sensors
        has_rsn_hr: Whether installation has RSN HR sensors
        has_debris: Whether installation has debris sensors

    Returns:
        InstallationParameters instance
    """
    query = """
        SELECT
            NdatiMedia, Ndatidespike, MEMStype,
            tolleranzaAcc, pos_inst, Tmax, Tmin,
            SEL, MEL
        FROM installation_parameters
        WHERE idTool = %s
    """
    results = conn.execute_query(query, (id_tool,))

    if not results:
        raise ValueError(f"No installation parameters found for tool {id_tool}")

    data = results[0]

    params = InstallationParameters(
        n_data_average=data.get('NdatiMedia', 60),
        n_data_despike=data.get('Ndatidespike', 3),
        mems_type=data.get('MEMStype', 1),
        acceleration_tolerance=data.get('tolleranzaAcc', 0.05),
        installation_position=data.get('pos_inst', 1),
        temp_max=data.get('Tmax', 80.0),
        temp_min=data.get('Tmin', -30.0),
        single_event_level=data.get('SEL', 10.0),
        multiple_event_level=data.get('MEL', 5.0)
    )

    logger.info(f"Loaded installation parameters for tool {id_tool}")
    return params


def load_calibration_data(
    control_unit_id: str,
    chain: str,
    node_list: List[int],
    sensor_type: str,
    conn: DatabaseConnection
) -> np.ndarray:
    """
    Load calibration data for sensors.

    Converts MATLAB letturaCal.m function.

    Args:
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of node IDs
        sensor_type: Type of sensor ('RSN', 'RSNHR', 'LL', etc.)
        conn: Database connection

    Returns:
        Numpy array with calibration data
    """
    calibration_data = []

    for node_id in node_list:
        query = """
            SELECT calibration_values
            FROM sensor_calibration
            WHERE IDcentralina = %s
              AND DTcatena = %s
              AND nodeID = %s
              AND sensorType = %s
            ORDER BY calibrationDate DESC
            LIMIT 1
        """
        results = conn.execute_query(
            query,
            (control_unit_id, chain, node_id, sensor_type)
        )

        if results:
            # Parse calibration values (assuming JSON or comma-separated)
            cal_values = results[0]['calibration_values']
            if isinstance(cal_values, str):
                cal_values = [float(x) for x in cal_values.split(',')]
            calibration_data.append(cal_values)
        else:
            logger.warning(f"No calibration data for node {node_id}, using defaults")
            # Default calibration values depend on sensor type
            if sensor_type == 'RSN':
                calibration_data.append([1.0, 0.0, 1.0, 0.0, 1.0, 0.0])
            elif sensor_type == 'RSNHR':
                calibration_data.append([1.0, 0.0, 1.0, 0.0])
            elif sensor_type == 'LL':
                calibration_data.append([1.0, 0.0])
            else:
                calibration_data.append([1.0, 0.0])

    logger.info(f"Loaded calibration data for {len(calibration_data)} {sensor_type} sensors")
    return np.array(calibration_data)


def get_node_types(
    chain: str,
    unit_id: int,
    conn: DatabaseConnection
) -> Tuple[int, List[int], List[int], List[int], List[int], List[int], List[int], List[int], List[int], List[int]]:
    """
    Get node types and counts for a chain.

    Converts MATLAB tipologiaNodi.m function.

    Args:
        chain: Chain identifier
        unit_id: Unit ID
        conn: Database connection

    Returns:
        Tuple with:
        - id_tool: Tool identifier
        - rsn_nodes: List of RSN Link node IDs
        - ss_nodes: List of Shock Sensor node IDs
        - rsn_hr_nodes: List of RSN HR node IDs
        - empty_list: Placeholder
        - ll_nodes: List of Load Link node IDs
        - trl_nodes: List of Trigger Link node IDs
        - gf_nodes: List of G-Flow node IDs
        - gs_nodes: List of G-Shock node IDs
        - dl_nodes: List of Debris Link node IDs
    """
    query = """
        SELECT idTool, nodeID, nodeType
        FROM chain_nodes
        WHERE unitID = %s AND chain = %s
        ORDER BY nodeOrder
    """
    results = conn.execute_query(query, (unit_id, chain))

    if not results:
        raise ValueError(f"No nodes found for unit {unit_id}, chain {chain}")

    id_tool = results[0]['idTool']

    # Organize nodes by type
    rsn_nodes = []
    ss_nodes = []
    rsn_hr_nodes = []
    ll_nodes = []
    trl_nodes = []
    gf_nodes = []
    gs_nodes = []
    dl_nodes = []

    for row in results:
        node_id = row['nodeID']
        node_type = row['nodeType']

        if node_type == 'RSN':
            rsn_nodes.append(node_id)
        elif node_type == 'SS':
            ss_nodes.append(node_id)
        elif node_type == 'RSNHR':
            rsn_hr_nodes.append(node_id)
        elif node_type == 'LL':
            ll_nodes.append(node_id)
        elif node_type == 'TrL':
            trl_nodes.append(node_id)
        elif node_type == 'GF':
            gf_nodes.append(node_id)
        elif node_type == 'GS':
            gs_nodes.append(node_id)
        elif node_type == 'DL':
            dl_nodes.append(node_id)

    logger.info(f"Found {len(rsn_nodes)} RSN, {len(ss_nodes)} SS, {len(rsn_hr_nodes)} RSNHR nodes")

    return (id_tool, rsn_nodes, ss_nodes, rsn_hr_nodes, [],
            ll_nodes, trl_nodes, gf_nodes, gs_nodes, dl_nodes)


def get_initial_date_time(
    chain: str,
    unit_id: int,
    conn: DatabaseConnection
) -> Tuple[str, str, int]:
    """
    Get initial date and time for data loading.

    Converts MATLAB datainiziale.m function.

    Args:
        chain: Chain identifier
        unit_id: Unit ID
        conn: Database connection

    Returns:
        Tuple with (date, time, unit_id)
    """
    query = """
        SELECT initialDate, initialTime
        FROM chain_configuration
        WHERE unitID = %s AND chain = %s
    """
    results = conn.execute_query(query, (unit_id, chain))

    if not results:
        raise ValueError(f"No configuration found for unit {unit_id}, chain {chain}")

    initial_date = results[0]['initialDate']
    initial_time = results[0]['initialTime']

    logger.info(f"Initial date/time: {initial_date} {initial_time}")
    return initial_date, initial_time, unit_id
