#!/usr/bin/env python3
"""
Altitude Analysis from Pressure Data
===================================
Calculates altitude from pressure readings, averages by minute, 
and plots overlay for matching time periods only.
"""

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime
import numpy as np
import os

def calculate_altitude_from_pressure(pressure_hpa, sea_level_pressure=1013.25):
    """
    Calculate altitude from barometric pressure using standard atmosphere formula
    Altitude (m) = 44330 * (1 - (P/P0)^(1/5.255))
    """
    return 44330 * (1 - (pressure_hpa / sea_level_pressure) ** (1/5.255))

def load_and_process_data():
    """Load and process both CSV files"""
    
    # File paths
    file1 = "temps_humid_pressure.csv"  # pool2 data (current directory)
    file2 = "../pool/temps_humid_pressure.csv"  # pool data
    
    # Check if files exist
    for file in [file1, file2]:
        if not os.path.exists(file):
            print(f"Error: File not found: {file}")
            return None
    
    # Read the CSV files
    print(f"Loading {file1}...")
    df1 = pd.read_csv(file1, skipinitialspace=True)
    
    print(f"Loading {file2}...")
    df2 = pd.read_csv(file2, skipinitialspace=True)
    
    # Clean the data - remove any rows where DATE or TIME might be invalid
    df1 = df1[df1['DATE'].str.contains(r'^\d{4}-\d{2}-\d{2}$', na=False)]
    df2 = df2[df2['DATE'].str.contains(r'^\d{4}-\d{2}-\d{2}$', na=False)]
    
    # Convert numeric columns to float
    numeric_cols = ['ATH_T', 'ATH_H', 'BMP_T', 'BMP_P', 'BMP_SLP', 'ALT', 'AD']
    for col in numeric_cols:
        if col in df1.columns:
            df1[col] = pd.to_numeric(df1[col], errors='coerce')
        if col in df2.columns:
            df2[col] = pd.to_numeric(df2[col], errors='coerce')
    
    # Calculate altitude from pressure for both datasets
    df1['Calc_Altitude'] = calculate_altitude_from_pressure(df1['BMP_P'])
    df2['Calc_Altitude'] = calculate_altitude_from_pressure(df2['BMP_P'])
    
    # Add source labels
    df1['Source'] = 'Pool2'
    df2['Source'] = 'Pool'
    
    # Combine DataFrames
    df = pd.concat([df1, df2], ignore_index=True)
    
    print(f"Combined data: {len(df)} total records")
    print(f"Pool data: {len(df2)} records")
    print(f"Pool2 data: {len(df1)} records")
    
    return df

def round_to_minute_and_average(df):
    """Round timestamps to nearest minute and average readings"""
    
    # Create datetime column with error handling
    try:
        df['DateTime'] = pd.to_datetime(df['DATE'] + ' ' + df['TIME'], errors='coerce')
    except:
        df['DateTime'] = pd.to_datetime(df['DATE'] + ' ' + df['TIME'], format='mixed', errors='coerce')
    
    # Remove rows where datetime parsing failed
    df = df.dropna(subset=['DateTime'])
    
    # Round to nearest minute
    df['MinuteRounded'] = df['DateTime'].dt.round('min')
    
    # Group by source and rounded minute, then average
    numeric_cols = ['ATH_T', 'ATH_H', 'BMP_T', 'BMP_P', 'BMP_SLP', 'ALT', 'AD', 'Calc_Altitude']
    
    averaged_df = df.groupby(['Source', 'MinuteRounded']).agg({
        **{col: 'mean' for col in numeric_cols},
        'DATE': 'first',
        'TIME': 'first'
    }).reset_index()
    
    print(f"After averaging by minute: {len(averaged_df)} records")
    
    return averaged_df

def create_altitude_overlay_plot(df):
    """Create overlay plots for altitude data - only for matching minutes"""
    
    # Find common minutes between both sources
    pool_minutes = set(df[df['Source'] == 'Pool']['MinuteRounded'])
    pool2_minutes = set(df[df['Source'] == 'Pool2']['MinuteRounded'])
    common_minutes = pool_minutes.intersection(pool2_minutes)
    
    print(f"\\nAltitude Analysis:")
    print(f"Common minutes found: {len(common_minutes)}")
    print(f"Pool minutes: {len(pool_minutes)}, Pool2 minutes: {len(pool2_minutes)}")
    
    if len(common_minutes) == 0:
        print("❌ No overlapping time periods found between datasets!")
        return None
    
    # Filter data to only common minutes
    df_common = df[df['MinuteRounded'].isin(common_minutes)].copy()
    
    # Pivot data for easier plotting
    calc_altitude = df_common.pivot(index='MinuteRounded', columns='Source', values='Calc_Altitude')
    sensor_altitude = df_common.pivot(index='MinuteRounded', columns='Source', values='ALT')
    pressure = df_common.pivot(index='MinuteRounded', columns='Source', values='BMP_P')
    
    # Create figure with 4 subplots - 1200px wide (12 inches at 100 DPI)
    fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(12, 20))
    
    # Color schemes
    pool_colors = {'calc': '#1f77b4', 'sensor': '#ff7f0e', 'pressure': '#2ca02c'}
    pool2_colors = {'calc': '#d62728', 'sensor': '#9467bd', 'pressure': '#8c564b'}
    
    # === CALCULATED ALTITUDE PLOT ===
    if 'Pool' in calc_altitude.columns and 'Pool2' in calc_altitude.columns:
        calc_altitude_clean = calc_altitude.dropna()
        
        if not calc_altitude_clean.empty:
            ax1.plot(calc_altitude_clean.index, calc_altitude_clean['Pool'], 
                    'o-', label='Pool (Calculated)', color=pool_colors['calc'], 
                    alpha=0.8, markersize=4, linewidth=2)
            ax1.plot(calc_altitude_clean.index, calc_altitude_clean['Pool2'], 
                    's-', label='Pool2 (Calculated)', color=pool2_colors['calc'], 
                    alpha=0.8, markersize=4, linewidth=2)
    
    ax1.set_title(f'Calculated Altitude from Pressure: Synchronized Data ({len(common_minutes)} matching minutes)', 
                  fontsize=14, fontweight='bold')
    ax1.set_ylabel('Altitude (meters)', fontsize=12)
    ax1.grid(True, alpha=0.3)
    ax1.legend(loc='upper right')
    ax1.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M'))
    ax1.xaxis.set_major_locator(mdates.HourLocator(interval=6))
    plt.setp(ax1.xaxis.get_majorticklabels(), rotation=45)
    
    # === SENSOR ALTITUDE PLOT ===
    if 'Pool' in sensor_altitude.columns and 'Pool2' in sensor_altitude.columns:
        sensor_altitude_clean = sensor_altitude.dropna()
        
        if not sensor_altitude_clean.empty:
            ax2.plot(sensor_altitude_clean.index, sensor_altitude_clean['Pool'], 
                    'o--', label='Pool (Sensor ALT)', color=pool_colors['sensor'], 
                    alpha=0.8, markersize=3, linewidth=1)
            ax2.plot(sensor_altitude_clean.index, sensor_altitude_clean['Pool2'], 
                    's--', label='Pool2 (Sensor ALT)', color=pool2_colors['sensor'], 
                    alpha=0.8, markersize=3, linewidth=1)
    
    ax2.set_title(f'Sensor-Reported Altitude: Synchronized Data', fontsize=14, fontweight='bold')
    ax2.set_ylabel('Altitude (meters)', fontsize=12)
    ax2.grid(True, alpha=0.3)
    ax2.legend(loc='upper right')
    ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M'))
    ax2.xaxis.set_major_locator(mdates.HourLocator(interval=6))
    plt.setp(ax2.xaxis.get_majorticklabels(), rotation=45)
    
    # === PRESSURE PLOT ===
    if 'Pool' in pressure.columns and 'Pool2' in pressure.columns:
        pressure_clean = pressure.dropna()
        
        if not pressure_clean.empty:
            ax3.plot(pressure_clean.index, pressure_clean['Pool'], 
                    'o-', label='Pool Pressure', color=pool_colors['pressure'], 
                    alpha=0.8, markersize=3, linewidth=2)
            ax3.plot(pressure_clean.index, pressure_clean['Pool2'], 
                    's-', label='Pool2 Pressure', color=pool2_colors['pressure'], 
                    alpha=0.8, markersize=3, linewidth=2)
    
    ax3.set_title(f'Barometric Pressure: Synchronized Data', fontsize=14, fontweight='bold')
    ax3.set_xlabel('Time', fontsize=12)
    ax3.set_ylabel('Pressure (hPa)', fontsize=12)
    ax3.grid(True, alpha=0.3)
    ax3.legend(loc='upper right')
    ax3.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M'))
    ax3.xaxis.set_major_locator(mdates.HourLocator(interval=6))
    plt.setp(ax3.xaxis.get_majorticklabels(), rotation=45)
    
    # === ALTITUDE DIFFERENCE PLOT (Pool2 - Pool) in FEET ===
    if 'Pool' in calc_altitude.columns and 'Pool2' in calc_altitude.columns:
        altitude_diff_clean = calc_altitude.dropna()
        
        if not altitude_diff_clean.empty:
            # Calculate difference: Pool2 - Pool (in meters, then convert to feet)
            altitude_diff_meters = altitude_diff_clean['Pool2'] - altitude_diff_clean['Pool']
            altitude_diff_feet = altitude_diff_meters * 3.28084  # Convert meters to feet
            
            # Plot the difference
            ax4.plot(altitude_diff_clean.index, altitude_diff_feet, 
                    'o-', label='Pool2 - Pool (feet)', color='purple', 
                    alpha=0.8, markersize=4, linewidth=2)
            
            # Add a horizontal line at zero
            ax4.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
            
            # Add statistics
            mean_diff = altitude_diff_feet.mean()
            std_diff = altitude_diff_feet.std()
            ax4.text(0.02, 0.98, f'Mean Difference: {mean_diff:+.1f} ft\\nStd Dev: {std_diff:.1f} ft', 
                     transform=ax4.transAxes, verticalalignment='top',
                     bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
    
    ax4.set_title(f'Altitude Difference (Pool2 - Pool): Calculated from Pressure', 
                  fontsize=14, fontweight='bold')
    ax4.set_xlabel('Time', fontsize=12)
    ax4.set_ylabel('Altitude Difference (feet)', fontsize=12)
    ax4.grid(True, alpha=0.3)
    ax4.legend(loc='upper right')
    ax4.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M'))
    ax4.xaxis.set_major_locator(mdates.HourLocator(interval=6))
    plt.setp(ax4.xaxis.get_majorticklabels(), rotation=45)
    
    plt.tight_layout()
    
    # Save plot - 1200px wide (12 inches at 100 DPI)
    output_file = 'altitude_pressure_analysis.png'
    plt.savefig(output_file, dpi=100, bbox_inches='tight')
    print(f"\\nAltitude analysis plot saved as: {output_file}")
    
    return fig, df_common

def print_altitude_statistics(df_common):
    """Print summary statistics for altitude analysis"""
    
    print("\\n=== ALTITUDE ANALYSIS STATISTICS ===")
    
    pool_data = df_common[df_common['Source'] == 'Pool']
    pool2_data = df_common[df_common['Source'] == 'Pool2']
    
    for source in df_common['Source'].unique():
        source_data = df_common[df_common['Source'] == source]
        print(f"\\n{source.upper()} ALTITUDE DATA:")
        print(f"  Records: {len(source_data)}")
        print(f"  Time Range: {source_data['MinuteRounded'].min()} to {source_data['MinuteRounded'].max()}")
        print(f"  Calculated Altitude: {source_data['Calc_Altitude'].mean():.1f}m ± {source_data['Calc_Altitude'].std():.1f}m")
        print(f"  Sensor Altitude: {source_data['ALT'].mean():.1f}m ± {source_data['ALT'].std():.1f}m")
        print(f"  Pressure: {source_data['BMP_P'].mean():.1f} hPa ± {source_data['BMP_P'].std():.1f} hPa")
        
        # Calculate altitude difference
        altitude_diff = source_data['Calc_Altitude'].mean() - source_data['ALT'].mean()
        altitude_diff_feet = altitude_diff * 3.28084
        print(f"  Altitude Difference (Calc - Sensor): {altitude_diff:+.1f}m ({altitude_diff_feet:+.1f}ft)")
    
    # Calculate difference between locations
    if len(pool_data) > 0 and len(pool2_data) > 0:
        pool_avg = pool_data['Calc_Altitude'].mean()
        pool2_avg = pool2_data['Calc_Altitude'].mean()
        location_diff_m = pool2_avg - pool_avg
        location_diff_ft = location_diff_m * 3.28084
        
        print(f"\\n=== LOCATION COMPARISON ===")
        print(f"Pool2 vs Pool Altitude Difference:")
        print(f"  {location_diff_m:+.1f} meters ({location_diff_ft:+.1f} feet)")
        print(f"  Pool2 is {'HIGHER' if location_diff_m > 0 else 'LOWER'} than Pool")

def main():
    """Main processing function"""
    
    try:
        # Load and process data
        df = load_and_process_data()
        if df is None:
            return
        
        # Round to minutes and average
        averaged_df = round_to_minute_and_average(df)
        
        # Create altitude overlay plots
        fig, df_common = create_altitude_overlay_plot(averaged_df)
        
        if df_common is not None:
            # Print statistics
            print_altitude_statistics(df_common)
            
            # Save processed data
            output_csv = 'altitude_analysis_data.csv'
            df_common.to_csv(output_csv, index=False)
            print(f"\\nProcessed altitude data saved as: {output_csv}")
        
        print(f"\\n✅ Altitude analysis complete!")
        print(f"   - Plot: altitude_pressure_analysis.png")
        
    except Exception as e:
        print(f"Error processing altitude data: {e}")
        import traceback
        traceback.print_exc()

if __name__ == "__main__":
    main()