"""
Main ATD (Automatic Data Acquisition) processing module.

Entry point for various sensor types including extensometers,
crackmeters, and other displacement sensors.
"""

import time
import logging
from typing import List
from ..common.database import DatabaseConfig, DatabaseConnection, get_unit_id
from ..common.logging_utils import setup_logger, log_elapsed_time
from ..common.config import load_installation_parameters, load_calibration_data
from .data_processing import (
    load_radial_link_data, define_radial_link_data,
    load_load_link_data, define_load_link_data,
    load_pressure_link_data, define_pressure_link_data,
    load_extensometer_3d_data, define_extensometer_3d_data,
    load_crackmeter_data, define_crackmeter_data,
    load_pcl_data, define_pcl_data,
    load_tube_link_data, define_tube_link_data
)
from .conversion import (
    convert_radial_link_data, convert_load_link_data,
    convert_pressure_link_data, convert_extensometer_data,
    convert_extensometer_3d_data, convert_crackmeter_data,
    convert_pcl_data, convert_tube_link_data
)
from .averaging import (
    average_radial_link_data, average_load_link_data,
    average_pressure_link_data, average_extensometer_data,
    average_extensometer_3d_data, average_crackmeter_data,
    average_pcl_data, average_tube_link_data
)
from .elaboration import (
    elaborate_radial_link_data, elaborate_load_link_data,
    elaborate_pressure_link_data, elaborate_extensometer_3d_data,
    elaborate_crackmeter_data, elaborate_pcl_data, elaborate_tube_link_data
)
from .db_write import (
    write_radial_link_data, write_load_link_data,
    write_pressure_link_data, write_extensometer_data,
    write_extensometer_3d_data, write_crackmeter_data,
    write_pcl_data, write_tube_link_data
)


def process_radial_link_sensors(conn, control_unit_id: str, chain: str,
                                node_list: List[int], params: dict,
                                logger: logging.Logger) -> bool:
    """
    Process RL (Radial Link) sensors.

    RL sensors measure 3D acceleration and magnetic field.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of RL node IDs
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} RL sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, 'RL', conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info("Loading RL raw data from database")
        raw_data = load_radial_link_data(conn, control_unit_id, chain,
                                        initial_date, initial_time, node_list)

        if raw_data is None or len(raw_data) == 0:
            logger.warning("No RL data found")
            return True

        # Define data structure
        logger.info("Structuring RL data")
        acceleration, magnetic_field, timestamps, temperature, err_flag, resultant = \
            define_radial_link_data(raw_data, n_sensors, n_despike, temp_max, temp_min)

        if acceleration is None:
            logger.warning("RL data definition failed")
            return True

        # Convert
        logger.info("Converting RL data")
        acc_converted, mag_converted, temp_converted, err_flag = convert_radial_link_data(
            acceleration, magnetic_field, temperature, calibration_data, n_sensors
        )

        # Average
        logger.info(f"Averaging RL data with {n_points} points")
        acc_avg, mag_avg, temp_avg, err_flag = average_radial_link_data(
            acc_converted, mag_converted, timestamps, temp_converted, n_points
        )

        # Elaborate
        logger.info("Elaborating RL data")
        x_global, y_global, z_global, x_local, y_local, z_local, \
        x_diff, y_diff, z_diff, err_flag = elaborate_radial_link_data(
            conn, control_unit_id, chain, n_sensors, acc_avg, mag_avg,
            temp_max, temp_min, temp_avg, err_flag, params
        )

        # Write to database
        logger.info("Writing RL data to database")
        write_radial_link_data(
            conn, control_unit_id, chain, x_global, y_global, z_global,
            x_local, y_local, z_local, x_diff, y_diff, z_diff,
            timestamps, node_list, temp_avg, err_flag
        )

        logger.info(f"RL processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing RL sensors: {e}", exc_info=True)
        return False


def process_load_link_sensors(conn, control_unit_id: str, chain: str,
                              node_list: List[int], params: dict,
                              logger: logging.Logger) -> bool:
    """
    Process LL (Load Link) sensors.

    LL sensors measure force/load.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of LL node IDs
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} LL sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, 'LL', conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info("Loading LL raw data from database")
        raw_data = load_load_link_data(conn, control_unit_id, chain,
                                      initial_date, initial_time, node_list)

        if raw_data is None or len(raw_data) == 0:
            logger.warning("No LL data found")
            return True

        # Define data structure
        logger.info("Structuring LL data")
        force_data, timestamps, temperature, err_flag = define_load_link_data(
            raw_data, n_sensors, n_despike, temp_max, temp_min
        )

        if force_data is None:
            logger.warning("LL data definition failed")
            return True

        # Convert
        logger.info("Converting LL data")
        force_converted, temp_converted, err_flag = convert_load_link_data(
            force_data, temperature, calibration_data, n_sensors
        )

        # Average
        logger.info(f"Averaging LL data with {n_points} points")
        force_avg, temp_avg, err_flag = average_load_link_data(
            force_converted, timestamps, temp_converted, n_points
        )

        # Elaborate
        logger.info("Elaborating LL data")
        force, force_diff, err_flag = elaborate_load_link_data(
            conn, control_unit_id, chain, n_sensors, force_avg,
            temp_max, temp_min, temp_avg, err_flag, params
        )

        # Write to database
        logger.info("Writing LL data to database")
        write_load_link_data(
            conn, control_unit_id, chain, force, force_diff,
            timestamps, node_list, temp_avg, err_flag
        )

        logger.info(f"LL processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing LL sensors: {e}", exc_info=True)
        return False


def process_pressure_link_sensors(conn, control_unit_id: str, chain: str,
                                  node_list: List[int], params: dict,
                                  logger: logging.Logger) -> bool:
    """
    Process PL (Pressure Link) sensors.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of PL node IDs
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} PL sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, 'PL', conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info("Loading PL raw data from database")
        raw_data = load_pressure_link_data(conn, control_unit_id, chain,
                                          initial_date, initial_time, node_list)

        if raw_data is None or len(raw_data) == 0:
            logger.warning("No PL data found")
            return True

        # Define data structure
        logger.info("Structuring PL data")
        pressure_data, timestamps, temperature, err_flag = define_pressure_link_data(
            raw_data, n_sensors, n_despike, temp_max, temp_min
        )

        if pressure_data is None:
            logger.warning("PL data definition failed")
            return True

        # Convert
        logger.info("Converting PL data")
        pressure_converted, temp_converted, err_flag = convert_pressure_link_data(
            pressure_data, temperature, calibration_data, n_sensors
        )

        # Average
        logger.info(f"Averaging PL data with {n_points} points")
        pressure_avg, temp_avg, err_flag = average_pressure_link_data(
            pressure_converted, timestamps, temp_converted, n_points
        )

        # Elaborate
        logger.info("Elaborating PL data")
        pressure, pressure_diff, err_flag = elaborate_pressure_link_data(
            conn, control_unit_id, chain, n_sensors, pressure_avg,
            temp_max, temp_min, temp_avg, err_flag, params
        )

        # Write to database
        logger.info("Writing PL data to database")
        write_pressure_link_data(
            conn, control_unit_id, chain, pressure, pressure_diff,
            timestamps, node_list, temp_avg, err_flag
        )

        logger.info(f"PL processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing PL sensors: {e}", exc_info=True)
        return False


def process_extensometer_3d_sensors(conn, control_unit_id: str, chain: str,
                                    node_list: List[int], params: dict,
                                    logger: logging.Logger) -> bool:
    """
    Process 3DEL (3D Extensometer) sensors.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of 3DEL node IDs
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} 3DEL sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, '3DEL', conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info("Loading 3DEL raw data from database")
        raw_data = load_extensometer_3d_data(conn, control_unit_id, chain,
                                            initial_date, initial_time, node_list)

        if raw_data is None or len(raw_data) == 0:
            logger.warning("No 3DEL data found")
            return True

        # Define data structure
        logger.info("Structuring 3DEL data")
        displacement_data, timestamps, temperature, err_flag = define_extensometer_3d_data(
            raw_data, n_sensors, n_despike, temp_max, temp_min
        )

        if displacement_data is None:
            logger.warning("3DEL data definition failed")
            return True

        # Convert
        logger.info("Converting 3DEL data")
        disp_converted, temp_converted, err_flag = convert_extensometer_3d_data(
            displacement_data, temperature, calibration_data, n_sensors
        )

        # Average
        logger.info(f"Averaging 3DEL data with {n_points} points")
        disp_avg, temp_avg, err_flag = average_extensometer_3d_data(
            disp_converted, timestamps, temp_converted, n_points
        )

        # Elaborate
        logger.info("Elaborating 3DEL data")
        x_disp, y_disp, z_disp, x_diff, y_diff, z_diff, err_flag = \
            elaborate_extensometer_3d_data(
                conn, control_unit_id, chain, n_sensors, disp_avg,
                temp_max, temp_min, temp_avg, err_flag, params
            )

        # Write to database
        logger.info("Writing 3DEL data to database")
        write_extensometer_3d_data(
            conn, control_unit_id, chain, x_disp, y_disp, z_disp,
            x_diff, y_diff, z_diff, timestamps, node_list, temp_avg, err_flag
        )

        logger.info(f"3DEL processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing 3DEL sensors: {e}", exc_info=True)
        return False


def process_crackmeter_sensors(conn, control_unit_id: str, chain: str,
                               node_list: List[int], sensor_type: str,
                               params: dict, logger: logging.Logger) -> bool:
    """
    Process crackmeter (CrL, 2DCrL, 3DCrL) sensors.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of CrL node IDs
        sensor_type: 'CrL' (1D), '2DCrL' (2D), or '3DCrL' (3D)
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        n_dimensions = {'CrL': 1, '2DCrL': 2, '3DCrL': 3}.get(sensor_type, 1)

        logger.info(f"Processing {n_sensors} {sensor_type} sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, sensor_type, conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info(f"Loading {sensor_type} raw data from database")
        raw_data = load_crackmeter_data(conn, control_unit_id, chain,
                                       initial_date, initial_time, node_list, sensor_type)

        if raw_data is None or len(raw_data) == 0:
            logger.warning(f"No {sensor_type} data found")
            return True

        # Define data structure
        logger.info(f"Structuring {sensor_type} data")
        displacement_data, timestamps, temperature, err_flag = define_crackmeter_data(
            raw_data, n_sensors, n_dimensions, n_despike, temp_max, temp_min
        )

        if displacement_data is None:
            logger.warning(f"{sensor_type} data definition failed")
            return True

        # Convert
        logger.info(f"Converting {sensor_type} data")
        disp_converted, temp_converted, err_flag = convert_crackmeter_data(
            displacement_data, temperature, calibration_data, n_sensors, n_dimensions
        )

        # Average
        logger.info(f"Averaging {sensor_type} data with {n_points} points")
        disp_avg, temp_avg, err_flag = average_crackmeter_data(
            disp_converted, timestamps, temp_converted, n_points
        )

        # Elaborate
        logger.info(f"Elaborating {sensor_type} data")
        displacement, displacement_diff, err_flag = elaborate_crackmeter_data(
            conn, control_unit_id, chain, n_sensors, disp_avg, n_dimensions,
            temp_max, temp_min, temp_avg, err_flag, params
        )

        # Write to database
        logger.info(f"Writing {sensor_type} data to database")
        write_crackmeter_data(
            conn, control_unit_id, chain, displacement, displacement_diff,
            timestamps, node_list, temp_avg, err_flag, n_dimensions, sensor_type
        )

        logger.info(f"{sensor_type} processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing {sensor_type} sensors: {e}", exc_info=True)
        return False


def process_pcl_sensors(conn, control_unit_id: str, chain: str,
                       node_list: List[int], sensor_type: str,
                       params: dict, logger: logging.Logger) -> bool:
    """
    Process PCL/PCLHR (Perimeter Cable Link) sensors.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of PCL node IDs
        sensor_type: 'PCL' or 'PCLHR'
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} {sensor_type} sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, sensor_type, conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info(f"Loading {sensor_type} raw data from database")
        raw_data = load_pcl_data(conn, control_unit_id, chain,
                                 initial_date, initial_time, node_list, sensor_type)

        if raw_data is None or len(raw_data) == 0:
            logger.warning(f"No {sensor_type} data found")
            return True

        # Define data structure
        logger.info(f"Structuring {sensor_type} data")
        angle_data, timestamps, temperature, err_flag = define_pcl_data(
            raw_data, n_sensors, n_despike, temp_max, temp_min
        )

        if angle_data is None:
            logger.warning(f"{sensor_type} data definition failed")
            return True

        # Convert
        logger.info(f"Converting {sensor_type} data")
        angles_converted, temp_converted, err_flag = convert_pcl_data(
            angle_data, temperature, calibration_data, n_sensors, sensor_type
        )

        # Average
        logger.info(f"Averaging {sensor_type} data with {n_points} points")
        angles_avg, temp_avg, err_flag = average_pcl_data(
            angles_converted, timestamps, temp_converted, n_points
        )

        # Elaborate (biaxial calculations)
        logger.info(f"Elaborating {sensor_type} data")
        y_disp, z_disp, y_local, z_local, alpha_x, alpha_y, y_diff, z_diff, err_flag = \
            elaborate_pcl_data(
                conn, control_unit_id, chain, n_sensors, angles_avg, sensor_type,
                temp_max, temp_min, temp_avg, err_flag, params
            )

        # Write to database
        logger.info(f"Writing {sensor_type} data to database")
        write_pcl_data(
            conn, control_unit_id, chain, y_disp, z_disp, y_local, z_local,
            alpha_x, alpha_y, y_diff, z_diff, timestamps, node_list, temp_avg, err_flag, sensor_type
        )

        logger.info(f"{sensor_type} processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing {sensor_type} sensors: {e}", exc_info=True)
        return False


def process_tube_link_sensors(conn, control_unit_id: str, chain: str,
                              node_list: List[int], params: dict,
                              logger: logging.Logger) -> bool:
    """
    Process TuL (Tube Link) sensors with 3D biaxial correlation.

    Args:
        conn: Database connection
        control_unit_id: Control unit identifier
        chain: Chain identifier
        node_list: List of TuL node IDs
        params: Installation parameters
        logger: Logger instance

    Returns:
        True if successful, False otherwise
    """
    try:
        n_sensors = len(node_list)
        logger.info(f"Processing {n_sensors} TuL sensors")

        # Load calibration data
        calibration_data = load_calibration_data(control_unit_id, chain, 'TuL', conn)

        # Get parameters
        initial_date = params.get('initial_date')
        initial_time = params.get('initial_time')
        n_points = params.get('n_points_avg', 100)
        n_despike = params.get('n_despike', 5)
        temp_max = params.get('temp_max', 80.0)
        temp_min = params.get('temp_min', -30.0)

        # Load raw data
        logger.info("Loading TuL raw data from database")
        raw_data = load_tube_link_data(conn, control_unit_id, chain,
                                       initial_date, initial_time, node_list)

        if raw_data is None or len(raw_data) == 0:
            logger.warning("No TuL data found")
            return True

        # Define data structure
        logger.info("Structuring TuL data")
        angle_data, timestamps, temperature, err_flag = define_tube_link_data(
            raw_data, n_sensors, n_despike, temp_max, temp_min
        )

        if angle_data is None:
            logger.warning("TuL data definition failed")
            return True

        # Convert
        logger.info("Converting TuL data")
        angles_converted, temp_converted, err_flag = convert_tube_link_data(
            angle_data, temperature, calibration_data, n_sensors
        )

        # Average
        logger.info(f"Averaging TuL data with {n_points} points")
        angles_avg, temp_avg, err_flag = average_tube_link_data(
            angles_converted, timestamps, temp_converted, n_points
        )

        # Elaborate (3D biaxial calculations with clockwise/counterclockwise)
        logger.info("Elaborating TuL data")
        x_disp, y_disp, z_disp, x_star, y_star, z_star, \
        x_local, y_local, z_local, x_diff, y_diff, z_diff, err_flag = \
            elaborate_tube_link_data(
                conn, control_unit_id, chain, n_sensors, angles_avg,
                temp_max, temp_min, temp_avg, err_flag, params
            )

        # Write to database
        logger.info("Writing TuL data to database")
        write_tube_link_data(
            conn, control_unit_id, chain, x_disp, y_disp, z_disp,
            x_star, y_star, z_star, x_local, y_local, z_local,
            x_diff, y_diff, z_diff, timestamps, node_list, temp_avg, err_flag
        )

        logger.info(f"TuL processing completed: {len(timestamps)} records")
        return True

    except Exception as e:
        logger.error(f"Error processing TuL sensors: {e}", exc_info=True)
        return False


def process_atd_chain(control_unit_id: str, chain: str) -> int:
    """
    Main function to process ATD chain data.

    Handles various sensor types:
    - RL: Radial Link
    - LL: Linear Link
    - PL: Pendulum Link
    - 3DEL: 3D Extensometer Link
    - MPBEL: Multi-Point Borehole Extensometer Link
    - CrL: Crackrometer Link
    - WEL: Wire Extensometer Link
    - SM: Settlement Marker
    - PCL: Perimeter Cable Link
    - TuL: Tube Link

    Args:
        control_unit_id: Control unit identifier
        chain: Chain identifier

    Returns:
        0 if successful, 1 if error
    """
    start_time = time.time()

    # Setup logger
    logger = setup_logger(control_unit_id, chain, "ATD")

    try:
        # Load database configuration
        db_config = DatabaseConfig()

        # Connect to database
        with DatabaseConnection(db_config) as conn:
            logger.info("Database connection established")

            # Get unit ID
            unit_id = get_unit_id(control_unit_id, conn)

            # Load sensor configuration
            query = """
                SELECT idTool, nodeID, nodeType, sensorModel, installationAngle, sensorLength
                FROM chain_nodes
                WHERE unitID = %s AND chain = %s
                  AND nodeType IN ('RL', 'LL', 'PL', '3DEL', 'MPBEL', 'CrL', '3DCrL', '2DCrL',
                                   'WEL', 'SM', 'PCL', 'PCLHR', 'TuL', 'TLH', 'TLHRH')
                ORDER BY nodeOrder
            """
            results = conn.execute_query(query, (unit_id, chain))

            if not results:
                logger.warning("No ATD sensors found for this chain")
                return 0

            id_tool = results[0]['idTool']

            # Organize sensors by type
            atd_sensors = {}
            for row in results:
                sensor_type = row['nodeType']
                if sensor_type not in atd_sensors:
                    atd_sensors[sensor_type] = []
                atd_sensors[sensor_type].append({
                    'nodeID': row['nodeID'],
                    'model': row.get('sensorModel'),
                    'angle': row.get('installationAngle', 0),
                    'length': row.get('sensorLength', 1.0)
                })

            logger.info(f"Found ATD sensors: {', '.join([f'{k}:{len(v)}' for k, v in atd_sensors.items()])}")

            # Load installation parameters
            params = load_installation_parameters(id_tool, conn)

            # Process each sensor type
            success = True

            # RL - Radial Link (3D acceleration + magnetometer)
            if 'RL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['RL']]
                if not process_radial_link_sensors(conn, control_unit_id, chain,
                                                  node_list, params, logger):
                    success = False

            # LL - Load Link (force sensors)
            if 'LL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['LL']]
                if not process_load_link_sensors(conn, control_unit_id, chain,
                                               node_list, params, logger):
                    success = False

            # PL - Pressure Link
            if 'PL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['PL']]
                if not process_pressure_link_sensors(conn, control_unit_id, chain,
                                                    node_list, params, logger):
                    success = False

            # 3DEL - 3D Extensometer Link
            if '3DEL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['3DEL']]
                if not process_extensometer_3d_sensors(conn, control_unit_id, chain,
                                                      node_list, params, logger):
                    success = False

            # CrL - Crackrometer Link (1D)
            if 'CrL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['CrL']]
                if not process_crackmeter_sensors(conn, control_unit_id, chain,
                                                 node_list, 'CrL', params, logger):
                    success = False

            # 2DCrL - 2D Crackrometer Link
            if '2DCrL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['2DCrL']]
                if not process_crackmeter_sensors(conn, control_unit_id, chain,
                                                 node_list, '2DCrL', params, logger):
                    success = False

            # 3DCrL - 3D Crackrometer Link
            if '3DCrL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['3DCrL']]
                if not process_crackmeter_sensors(conn, control_unit_id, chain,
                                                 node_list, '3DCrL', params, logger):
                    success = False

            # PCL - Perimeter Cable Link (biaxial calculations)
            if 'PCL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['PCL']]
                if not process_pcl_sensors(conn, control_unit_id, chain,
                                          node_list, 'PCL', params, logger):
                    success = False

            # PCLHR - Perimeter Cable Link High Resolution
            if 'PCLHR' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['PCLHR']]
                if not process_pcl_sensors(conn, control_unit_id, chain,
                                          node_list, 'PCLHR', params, logger):
                    success = False

            # TuL - Tube Link (3D biaxial calculations with correlation)
            if 'TuL' in atd_sensors:
                node_list = [s['nodeID'] for s in atd_sensors['TuL']]
                if not process_tube_link_sensors(conn, control_unit_id, chain,
                                                node_list, params, logger):
                    success = False

            # Log completion status
            if success:
                logger.info("ATD processing completed successfully")
            else:
                logger.warning("ATD processing completed with errors")

        # Log elapsed time
        elapsed = time.time() - start_time
        log_elapsed_time(logger, elapsed)

        return 0 if success else 1

    except Exception as e:
        logger.error(f"Error processing ATD chain: {e}", exc_info=True)
        return 1


if __name__ == "__main__":
    import sys

    if len(sys.argv) < 3:
        print("Usage: python -m src.atd.main <control_unit_id> <chain>")
        sys.exit(1)

    control_unit_id = sys.argv[1]
    chain = sys.argv[2]

    exit_code = process_atd_chain(control_unit_id, chain)
    sys.exit(exit_code)
