"""
Alert and monitoring system.

Handles threshold checking, alarm generation, and notification dispatch.
"""

import numpy as np
import logging
from typing import List, Dict, Any, Optional
from datetime import datetime
from ..common.database import DatabaseConnection

logger = logging.getLogger(__name__)


def check_alert_levels(
    control_unit_id: str,
    chain: str,
    timestamps_trl: np.ndarray,
    timestamps_ss: np.ndarray,
    timestamps_rsn: np.ndarray,
    timestamps_rsn_hr: np.ndarray,
    timestamps_ll: np.ndarray,
    timestamps_gf: np.ndarray,
    timestamps_gs: np.ndarray,
    initial_date_rsn: str,
    single_event_level: float,
    multiple_event_level: float,
    trigger_values: Optional[np.ndarray],
    shock_values: Optional[np.ndarray],
    load_values: Optional[np.ndarray],
    gflow_values: Optional[np.ndarray],
    gshock_values: Optional[np.ndarray],
    n_sensors_trl: int,
    n_sensors_rsn: int,
    n_sensors_rsn_hr: int,
    n_sensors_ll: int,
    has_trl: bool,
    has_ss: bool,
    has_rsn: bool,
    has_rsn_hr: bool,
    has_ll: bool,
    has_gf: bool,
    has_gs: bool,
    site_name: str,
    current_date: str,
    conn: DatabaseConnection
) -> bool:
    """
    Check sensor values against alert thresholds.

    Converts MATLAB alert_Levels.m function.

    Args:
        control_unit_id: Control unit identifier
        chain: Chain identifier
        timestamps_*: Timestamp arrays for each sensor type
        initial_date_rsn: Initial processing date
        single_event_level: Single event alarm threshold
        multiple_event_level: Multiple event alarm threshold
        *_values: Sensor value arrays
        n_sensors_*: Number of sensors of each type
        has_*: Flags indicating which sensor types are active
        site_name: Site name for notifications
        current_date: Current processing date
        conn: Database connection

    Returns:
        True if siren should be activated, False otherwise
    """
    logger.info("Checking alert levels")

    siren_on = False
    alerts_triggered = []

    # Check Trigger Link sensors
    if has_trl and trigger_values is not None:
        for i in range(n_sensors_trl):
            # Check recent values
            recent_window = 10  # Last 10 measurements
            if len(trigger_values) >= recent_window:
                recent_sum = np.sum(trigger_values[-recent_window:, i])

                if recent_sum >= single_event_level:
                    alert = {
                        'sensor_type': 'TriggerLink',
                        'sensor_id': i + 1,
                        'level': 'CRITICAL',
                        'value': recent_sum,
                        'threshold': single_event_level,
                        'timestamp': timestamps_trl[-1] if len(timestamps_trl) > 0 else None
                    }
                    alerts_triggered.append(alert)
                    siren_on = True
                    logger.warning(f"TriggerLink {i+1}: CRITICAL alert - {recent_sum} events")

                elif recent_sum >= multiple_event_level:
                    alert = {
                        'sensor_type': 'TriggerLink',
                        'sensor_id': i + 1,
                        'level': 'WARNING',
                        'value': recent_sum,
                        'threshold': multiple_event_level,
                        'timestamp': timestamps_trl[-1] if len(timestamps_trl) > 0 else None
                    }
                    alerts_triggered.append(alert)
                    logger.warning(f"TriggerLink {i+1}: WARNING alert - {recent_sum} events")

    # Check Shock Sensor
    if has_ss and shock_values is not None:
        for i in range(shock_values.shape[1]):
            recent_window = 10
            if len(shock_values) >= recent_window:
                recent_sum = np.sum(shock_values[-recent_window:, i])

                if recent_sum >= single_event_level:
                    alert = {
                        'sensor_type': 'ShockSensor',
                        'sensor_id': i + 1,
                        'level': 'CRITICAL',
                        'value': recent_sum,
                        'threshold': single_event_level,
                        'timestamp': timestamps_ss[-1] if len(timestamps_ss) > 0 else None
                    }
                    alerts_triggered.append(alert)
                    siren_on = True
                    logger.warning(f"ShockSensor {i+1}: CRITICAL alert")

    # Check Load Link sensors
    if has_ll and load_values is not None:
        # Check for threshold exceedance
        query = """
            SELECT nodeID, warningThreshold, criticalThreshold
            FROM sensor_thresholds
            WHERE IDcentralina = %s AND DTcatena = %s AND sensorType = 'LL'
        """
        thresholds = conn.execute_query(query, (control_unit_id, chain))

        for thresh in thresholds:
            node_idx = thresh['nodeID'] - 1
            if node_idx < load_values.shape[1]:
                current_value = load_values[-1, node_idx]

                if current_value >= thresh['criticalThreshold']:
                    alert = {
                        'sensor_type': 'LoadLink',
                        'sensor_id': thresh['nodeID'],
                        'level': 'CRITICAL',
                        'value': current_value,
                        'threshold': thresh['criticalThreshold'],
                        'timestamp': timestamps_ll[-1] if len(timestamps_ll) > 0 else None
                    }
                    alerts_triggered.append(alert)
                    siren_on = True
                    logger.warning(f"LoadLink {thresh['nodeID']}: CRITICAL alert - {current_value}")

                elif current_value >= thresh['warningThreshold']:
                    alert = {
                        'sensor_type': 'LoadLink',
                        'sensor_id': thresh['nodeID'],
                        'level': 'WARNING',
                        'value': current_value,
                        'threshold': thresh['warningThreshold'],
                        'timestamp': timestamps_ll[-1] if len(timestamps_ll) > 0 else None
                    }
                    alerts_triggered.append(alert)
                    logger.warning(f"LoadLink {thresh['nodeID']}: WARNING alert - {current_value}")

    # Store alerts in database
    if alerts_triggered:
        store_alerts(conn, control_unit_id, chain, alerts_triggered)

    return siren_on


def store_alerts(
    conn: DatabaseConnection,
    control_unit_id: str,
    chain: str,
    alerts: List[Dict[str, Any]]
) -> None:
    """
    Store triggered alerts in database.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        alerts: List of alert dictionaries
    """
    query = """
        INSERT INTO sensor_alerts
        (IDcentralina, DTcatena, sensorType, sensorID, alertLevel,
         alertValue, threshold, alertTimestamp, createdAt)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
    """

    data_rows = []
    for alert in alerts:
        data_rows.append((
            control_unit_id,
            chain,
            alert['sensor_type'],
            alert['sensor_id'],
            alert['level'],
            alert['value'],
            alert['threshold'],
            alert['timestamp'],
            datetime.now()
        ))

    if data_rows:
        conn.execute_many(query, data_rows)
        logger.info(f"Stored {len(data_rows)} alerts")


def activate_siren(
    alarms_config: Dict[str, Any],
    initial_dates: Dict[str, str],
    initial_times: Dict[str, str],
    timestamps: Dict[str, np.ndarray],
    siren_on: bool,
    conn: DatabaseConnection,
    current_date: str,
    current_time: str
) -> None:
    """
    Activate physical alarm devices (sirens, lights, etc.).

    Converts MATLAB Siren.m function.

    Args:
        alarms_config: Alarm device configuration
        initial_dates: Initial dates for each sensor type
        initial_times: Initial times for each sensor type
        timestamps: Timestamp arrays for each sensor type
        siren_on: Whether siren should be activated
        conn: Database connection
        current_date: Current date
        current_time: Current time
    """
    logger.info(f"Siren activation check: {siren_on}")

    if siren_on:
        # Query for alarm device configuration
        query = """
            SELECT deviceID, deviceType, activationCommand
            FROM alarm_devices
            WHERE active = 1
        """
        devices = conn.execute_query(query)

        for device in devices:
            try:
                # Send activation command to device
                # This would typically interface with hardware or external API
                logger.info(f"Activating alarm device: {device['deviceType']} (ID: {device['deviceID']})")

                # Log activation in database
                log_query = """
                    INSERT INTO alarm_activations
                    (deviceID, activationTimestamp, reason)
                    VALUES (%s, %s, %s)
                """
                conn.execute_update(
                    log_query,
                    (device['deviceID'], datetime.now(), 'Threshold exceeded')
                )

            except Exception as e:
                logger.error(f"Error activating device {device['deviceID']}: {e}")
    else:
        logger.info("No alarm activation required")
