"""
Main validation orchestrator for comparing Python and MATLAB outputs.

Provides high-level validation functions for different sensor types.
"""

import logging
from typing import Optional, List, Dict
from datetime import datetime
from .comparator import DataComparator, ValidationReport, ComparisonStatus
from .db_extractor import DataExtractor
from ..common.database import DatabaseConnection

logger = logging.getLogger(__name__)


class OutputValidator:
    """
    Validates Python implementation against MATLAB by comparing database outputs.

    This assumes:
    1. MATLAB has already processed the data and written to database
    2. Python processes the SAME raw data
    3. Both outputs are in the same database tables
    4. We can distinguish them by timestamp or by running them separately
    """

    def __init__(self,
                 conn: DatabaseConnection,
                 abs_tol: float = 1e-6,
                 rel_tol: float = 1e-4,
                 max_rel_tol: float = 0.01):
        """
        Initialize validator.

        Args:
            conn: Database connection
            abs_tol: Absolute tolerance for numerical comparison
            rel_tol: Relative tolerance for numerical comparison
            max_rel_tol: Maximum acceptable relative difference (1% default)
        """
        self.conn = conn
        self.extractor = DataExtractor(conn)
        self.comparator = DataComparator(abs_tol, rel_tol, max_rel_tol)
        self.report = ValidationReport()

    def validate_rsn(self,
                     control_unit_id: str,
                     chain: str,
                     matlab_timestamp: Optional[str] = None,
                     python_timestamp: Optional[str] = None) -> ValidationReport:
        """
        Validate RSN sensor output.

        Args:
            control_unit_id: Control unit identifier
            chain: Chain identifier
            matlab_timestamp: Specific timestamp for MATLAB data (EventDate)
            python_timestamp: Specific timestamp for Python data (EventDate)

        Returns:
            ValidationReport with comparison results
        """
        logger.info(f"Validating RSN data for {control_unit_id}/{chain}")

        # Extract data
        matlab_data = self.extractor.extract_rsn_data(
            control_unit_id, chain,
            start_date=matlab_timestamp, end_date=matlab_timestamp
        )
        python_data = self.extractor.extract_rsn_data(
            control_unit_id, chain,
            start_date=python_timestamp, end_date=python_timestamp
        )

        if not matlab_data:
            logger.warning("No MATLAB data found")
            return self.report

        if not python_data:
            logger.warning("No Python data found")
            return self.report

        # Compare records
        key_fields = ['NodeNum', 'EventDate', 'EventTime']
        value_fields = ['RollAngle', 'InclinAngle', 'AzimuthAngle',
                       'RollAngleDiff', 'InclinAngleDiff', 'AzimuthAngleDiff',
                       'T_node']

        results = self.comparator.compare_records(
            matlab_data, python_data, key_fields, value_fields
        )
        self.report.add_results(results)

        logger.info(f"RSN validation complete: {len(results)} comparisons")
        return self.report

    def validate_tilt(self,
                     control_unit_id: str,
                     chain: str,
                     sensor_type: str,
                     matlab_timestamp: Optional[str] = None,
                     python_timestamp: Optional[str] = None) -> ValidationReport:
        """
        Validate Tilt sensor output.

        Args:
            control_unit_id: Control unit identifier
            chain: Chain identifier
            sensor_type: Sensor type (TLHR, BL, PL, KLHR)
            matlab_timestamp: Specific timestamp for MATLAB data
            python_timestamp: Specific timestamp for Python data

        Returns:
            ValidationReport with comparison results
        """
        logger.info(f"Validating Tilt {sensor_type} data for {control_unit_id}/{chain}")

        # Extract data
        matlab_data = self.extractor.extract_tilt_data(
            control_unit_id, chain, sensor_type,
            start_date=matlab_timestamp, end_date=matlab_timestamp
        )
        python_data = self.extractor.extract_tilt_data(
            control_unit_id, chain, sensor_type,
            start_date=python_timestamp, end_date=python_timestamp
        )

        if not matlab_data or not python_data:
            logger.warning("Insufficient data for comparison")
            return self.report

        # Compare records
        key_fields = ['NodeNum', 'EventDate', 'EventTime']
        value_fields = ['X', 'Y', 'Z', 'X_local', 'Y_local', 'Z_local',
                       'XShift', 'YShift', 'ZShift', 'T_node']

        results = self.comparator.compare_records(
            matlab_data, python_data, key_fields, value_fields
        )
        self.report.add_results(results)

        logger.info(f"Tilt {sensor_type} validation complete: {len(results)} comparisons")
        return self.report

    def validate_atd_radial_link(self,
                                 control_unit_id: str,
                                 chain: str,
                                 matlab_timestamp: Optional[str] = None,
                                 python_timestamp: Optional[str] = None) -> ValidationReport:
        """
        Validate ATD Radial Link output.

        Args:
            control_unit_id: Control unit identifier
            chain: Chain identifier
            matlab_timestamp: Specific timestamp for MATLAB data
            python_timestamp: Specific timestamp for Python data

        Returns:
            ValidationReport with comparison results
        """
        logger.info(f"Validating ATD RL data for {control_unit_id}/{chain}")

        matlab_data = self.extractor.extract_atd_radial_link_data(
            control_unit_id, chain,
            start_date=matlab_timestamp, end_date=matlab_timestamp
        )
        python_data = self.extractor.extract_atd_radial_link_data(
            control_unit_id, chain,
            start_date=python_timestamp, end_date=python_timestamp
        )

        if not matlab_data or not python_data:
            logger.warning("Insufficient data for comparison")
            return self.report

        key_fields = ['NodeNum', 'EventDate', 'EventTime']
        value_fields = ['X', 'Y', 'Z', 'X_local', 'Y_local', 'Z_local',
                       'XShift', 'YShift', 'ZShift', 'T_node']

        results = self.comparator.compare_records(
            matlab_data, python_data, key_fields, value_fields
        )
        self.report.add_results(results)

        logger.info(f"ATD RL validation complete: {len(results)} comparisons")
        return self.report

    def validate_atd_load_link(self,
                               control_unit_id: str,
                               chain: str,
                               matlab_timestamp: Optional[str] = None,
                               python_timestamp: Optional[str] = None) -> ValidationReport:
        """Validate ATD Load Link output."""
        logger.info(f"Validating ATD LL data for {control_unit_id}/{chain}")

        matlab_data = self.extractor.extract_atd_load_link_data(
            control_unit_id, chain,
            start_date=matlab_timestamp, end_date=matlab_timestamp
        )
        python_data = self.extractor.extract_atd_load_link_data(
            control_unit_id, chain,
            start_date=python_timestamp, end_date=python_timestamp
        )

        if not matlab_data or not python_data:
            logger.warning("Insufficient data for comparison")
            return self.report

        key_fields = ['NodeNum', 'EventDate', 'EventTime']
        value_fields = ['Load', 'LoadDiff', 'T_node']

        results = self.comparator.compare_records(
            matlab_data, python_data, key_fields, value_fields
        )
        self.report.add_results(results)

        logger.info(f"ATD LL validation complete: {len(results)} comparisons")
        return self.report

    def validate_atd_pressure_link(self,
                                   control_unit_id: str,
                                   chain: str,
                                   matlab_timestamp: Optional[str] = None,
                                   python_timestamp: Optional[str] = None) -> ValidationReport:
        """Validate ATD Pressure Link output."""
        logger.info(f"Validating ATD PL data for {control_unit_id}/{chain}")

        matlab_data = self.extractor.extract_atd_pressure_link_data(
            control_unit_id, chain,
            start_date=matlab_timestamp, end_date=matlab_timestamp
        )
        python_data = self.extractor.extract_atd_pressure_link_data(
            control_unit_id, chain,
            start_date=python_timestamp, end_date=python_timestamp
        )

        if not matlab_data or not python_data:
            logger.warning("Insufficient data for comparison")
            return self.report

        key_fields = ['NodeNum', 'EventDate', 'EventTime']
        value_fields = ['Pressure', 'PressureDiff', 'T_node']

        results = self.comparator.compare_records(
            matlab_data, python_data, key_fields, value_fields
        )
        self.report.add_results(results)

        logger.info(f"ATD PL validation complete: {len(results)} comparisons")
        return self.report

    def validate_all(self,
                     control_unit_id: str,
                     chain: str,
                     matlab_timestamp: Optional[str] = None,
                     python_timestamp: Optional[str] = None) -> ValidationReport:
        """
        Run validation for all available sensor types in the chain.

        Args:
            control_unit_id: Control unit identifier
            chain: Chain identifier
            matlab_timestamp: Timestamp for MATLAB data
            python_timestamp: Timestamp for Python data

        Returns:
            ValidationReport with all comparison results
        """
        logger.info(f"Running comprehensive validation for {control_unit_id}/{chain}")

        # Try RSN
        try:
            self.validate_rsn(control_unit_id, chain, matlab_timestamp, python_timestamp)
        except Exception as e:
            logger.warning(f"RSN validation failed: {e}")

        # Try Tilt types
        for sensor_type in ['TLHR', 'BL', 'PL', 'KLHR']:
            try:
                self.validate_tilt(control_unit_id, chain, sensor_type,
                                  matlab_timestamp, python_timestamp)
            except Exception as e:
                logger.warning(f"Tilt {sensor_type} validation failed: {e}")

        # Try ATD types
        try:
            self.validate_atd_radial_link(control_unit_id, chain,
                                         matlab_timestamp, python_timestamp)
        except Exception as e:
            logger.warning(f"ATD RL validation failed: {e}")

        try:
            self.validate_atd_load_link(control_unit_id, chain,
                                       matlab_timestamp, python_timestamp)
        except Exception as e:
            logger.warning(f"ATD LL validation failed: {e}")

        try:
            self.validate_atd_pressure_link(control_unit_id, chain,
                                           matlab_timestamp, python_timestamp)
        except Exception as e:
            logger.warning(f"ATD PL validation failed: {e}")

        logger.info(f"Comprehensive validation complete")
        return self.report
