"""
GLODAP Data Loader
Global Ocean Data Analysis Project - Ocean carbonate chemistry
"""

import csv
import os
import math
from typing import Dict, List, Optional


class GLODAPLoader:
    """
    Loader for GLODAP ocean carbonate chemistry data
    """
    
    def __init__(self, data_dir: str = "./data"):
        """
        Initialize GLODAP loader
        
        Parameters
        ----------
        data_dir : str
            Base data directory
        """
        self.data_dir = data_dir
        self.glodap_dir = f"{data_dir}/glodap"
        self.data = []
        self._load_reference_data()
    
    def _load_reference_data(self):
        """Load reference data from research paper"""
        # Global ocean chemistry reference
        self.chemistry_ref = {
            1972: {'DIC': 2150, 'alkalinity': 2350, 'pH': 8.15, 'R': 10.3},
            1980: {'DIC': 2165, 'alkalinity': 2348, 'pH': 8.12, 'R': 10.7},
            1990: {'DIC': 2180, 'alkalinity': 2345, 'pH': 8.09, 'R': 11.1},
            2000: {'DIC': 2195, 'alkalinity': 2342, 'pH': 8.06, 'R': 11.5},
            2010: {'DIC': 2210, 'alkalinity': 2339, 'pH': 8.03, 'R': 11.9},
            2020: {'DIC': 2225, 'alkalinity': 2336, 'pH': 8.00, 'R': 12.2},
            2025: {'DIC': 2232, 'alkalinity': 2334, 'pH': 7.98, 'R': 12.4}
        }
        
        # Regional data
        self.regional_chemistry = {
            'north_atlantic': {
                'DIC_2025': 2250,
                'alkalinity_2025': 2350,
                'pH_2025': 7.95,
                'R_2025': 12.8
            },
            'south_atlantic': {
                'DIC_2025': 2220,
                'alkalinity_2025': 2330,
                'pH_2025': 8.00,
                'R_2025': 12.3
            },
            'north_pacific': {
                'DIC_2025': 2260,
                'alkalinity_2025': 2320,
                'pH_2025': 7.92,
                'R_2025': 13.1
            },
            'south_pacific': {
                'DIC_2025': 2215,
                'alkalinity_2025': 2325,
                'pH_2025': 8.02,
                'R_2025': 12.1
            },
            'indian': {
                'DIC_2025': 2225,
                'alkalinity_2025': 2335,
                'pH_2025': 8.01,
                'R_2025': 12.2
            },
            'southern': {
                'DIC_2025': 2190,
                'alkalinity_2025': 2310,
                'pH_2025': 8.05,
                'R_2025': 11.8
            }
        }
        
        # Total measurements
        self.total_measurements = 1200000  # 1.2 million
        
    def load_from_file(self, filepath: str) -> List[Dict]:
        """
        Load GLODAP data from CSV file
        
        Parameters
        ----------
        filepath : str
            Path to CSV file
        
        Returns
        -------
        list
            List of chemistry records
        """
        if not os.path.exists(filepath):
            return self._generate_synthetic_data()
        
        data = []
        with open(filepath, 'r') as f:
            reader = csv.DictReader(f)
            for row in reader:
                record = {}
                for key, value in row.items():
                    try:
                        record[key] = float(value)
                    except ValueError:
                        record[key] = value
                data.append(record)
        
        self.data = data
        return data
    
    def _generate_synthetic_data(self, n: int = 100) -> List[Dict]:
        """Generate synthetic GLODAP data for testing"""
        data = []
        
        for year in [1972, 1980, 1990, 2000, 2010, 2020, 2025]:
            if year in self.chemistry_ref:
                rec = self.chemistry_ref[year].copy()
                rec['year'] = year
                data.append(rec)
        
        return data
    
    def get_revelle_factor(self, year: int, region: Optional[str] = None) -> float:
        """
        Get Revelle Factor for given year and region
        
        Parameters
        ----------
        year : int
            Target year
        region : str, optional
            Ocean region
        
        Returns
        -------
        float
            Revelle Factor R
        """
        if region and region in self.regional_chemistry:
            return self.regional_chemistry[region]['R_2025']
        
        # Find closest year
        years = sorted(self.chemistry_ref.keys())
        closest = min(years, key=lambda y: abs(y - year))
        return self.chemistry_ref[closest]['R']
    
    def get_buffer_capacity(self, year: int, region: Optional[str] = None) -> float:
        """
        Get buffer capacity β = 1/R
        
        Parameters
        ----------
        year : int
            Target year
        region : str, optional
            Ocean region
        
        Returns
        -------
        float
            Buffer capacity β
        """
        R = self.get_revelle_factor(year, region)
        return 1.0 / R
    
    def get_dic(self, year: int, region: Optional[str] = None) -> float:
        """
        Get Dissolved Inorganic Carbon
        
        Parameters
        ----------
        year : int
            Target year
        region : str, optional
            Ocean region
        
        Returns
        -------
        float
            DIC in µmol/kg
        """
        if region and region in self.regional_chemistry:
            return self.regional_chemistry[region]['DIC_2025']
        
        years = sorted(self.chemistry_ref.keys())
        closest = min(years, key=lambda y: abs(y - year))
        return self.chemistry_ref[closest]['DIC']
    
    def get_alkalinity(self, year: int, region: Optional[str] = None) -> float:
        """
        Get Total Alkalinity
        
        Parameters
        ----------
        year : int
            Target year
        region : str, optional
            Ocean region
        
        Returns
        -------
        float
            Alkalinity in µmol/kg
        """
        if region and region in self.regional_chemistry:
            return self.regional_chemistry[region]['alkalinity_2025']
        
        years = sorted(self.chemistry_ref.keys())
        closest = min(years, key=lambda y: abs(y - year))
        return self.chemistry_ref[closest]['alkalinity']
    
    def get_ph(self, year: int, region: Optional[str] = None) -> float:
        """
        Get ocean pH
        
        Parameters
        ----------
        year : int
            Target year
        region : str, optional
            Ocean region
        
        Returns
        -------
        float
            pH value
        """
        if region and region in self.regional_chemistry:
            return self.regional_chemistry[region]['pH_2025']
        
        years = sorted(self.chemistry_ref.keys())
        closest = min(years, key=lambda y: abs(y - year))
        return self.chemistry_ref[closest]['pH']
    
    def compute_revelle_from_chemistry(self, DIC: float, alkalinity: float,
                                      temperature: float = 20.0,
                                      salinity: float = 35.0) -> float:
        """
        Compute Revelle Factor from carbonate chemistry (simplified)
        
        R = (∂ln pCO₂) / (∂ln DIC)
        
        Parameters
        ----------
        DIC : float
            Dissolved Inorganic Carbon (µmol/kg)
        alkalinity : float
            Total Alkalinity (µmol/kg)
        temperature : float
            Temperature (°C)
        salinity : float
            Salinity (PSU)
        
        Returns
        -------
        float
            Revelle Factor estimate
        """
        # Simplified calculation based on empirical relationship
        # From paper: R ≈ 9.1 + 0.015*(DIC - 2000) + 0.1*(20 - temperature)
        
        R = 9.1 + 0.015 * (DIC - 2000) + 0.1 * (20 - temperature)
        
        return R
    
    def get_acidification_rate(self, period: Tuple[int, int] = (1972, 2025)) -> float:
        """
        Get ocean acidification rate
        
        Parameters
        ----------
        period : tuple
            (start_year, end_year)
        
        Returns
        -------
        float
            pH change per decade
        """
        start_ph = self.get_ph(period[0])
        end_ph = self.get_ph(period[1])
        
        years = period[1] - period[0]
        decades = years / 10
        
        return (end_ph - start_ph) / decades
    
    def summary(self) -> str:
        """Print summary of GLODAP data"""
        current = self.chemistry_ref[2025]
        pre_ind = self.chemistry_ref[1972]
        
        acid_rate = self.get_acidification_rate()
        
        summary = f"""
╔════════════════════════════════════════════════════════════════╗
║                    GLODAP Ocean Chemistry Summary              ║
╠════════════════════════════════════════════════════════════════╣
║  Measurements      : {self.total_measurements/1e6:.1f} million                    ║
╠════════════════════════════════════════════════════════════════╣
║  Current (2025):                                              ║
║    DIC           : {current['DIC']} µmol/kg                        ║
║    Alkalinity    : {current['alkalinity']} µmol/kg                        ║
║    pH            : {current['pH']:.2f}                               ║
║    Revelle Factor: {current['R']:.1f}                               ║
╠════════════════════════════════════════════════════════════════╣
║  Change since 1972:                                           ║
║    DIC increase  : +{current['DIC'] - pre_ind['DIC']} µmol/kg                    ║
║    pH decrease   : {pre_ind['pH'] - current['pH']:.2f} units                     ║
║    Acidification rate: {acid_rate:.3f} pH/decade                ║
║    Buffer loss   : {(1/current['R'] - 1/pre_ind['R'])*100:.1f}%                  ║
╚════════════════════════════════════════════════════════════════╝
        """
        return summary
