"""
MODIS Data Loader
Moderate Resolution Imaging Spectroradiometer - NPP and vegetation data
"""

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


class MODISLoader:
    """
    Loader for MODIS NPP and vegetation data
    """
    
    def __init__(self, data_dir: str = "./data"):
        """
        Initialize MODIS loader
        
        Parameters
        ----------
        data_dir : str
            Base data directory
        """
        self.data_dir = data_dir
        self.modis_dir = f"{data_dir}/modis"
        self.data = []
        self._load_reference_data()
    
    def _load_reference_data(self):
        """Load reference data from research paper"""
        # Global NPP reference (PgC/yr)
        self.npp_ref = {
            2000: 58.5,
            2005: 58.4,
            2010: 58.4,
            2015: 58.3,
            2020: 58.3,
            2025: 58.3
        }
        
        # Biome-specific NPP (gC/m²/yr)
        self.biome_npp = {
            'tropical_rainforest': 1200,
            'tropical_savanna': 650,
            'temperate_forest': 800,
            'boreal_forest': 350,
            'temperate_grassland': 400,
            'shrubland': 250,
            'cropland': 550,
            'tundra': 150,
            'desert': 50
        }
        
        # Land cover fractions
        self.land_cover = {
            'tropical_rainforest': 0.12,
            'tropical_savanna': 0.15,
            'temperate_forest': 0.10,
            'boreal_forest': 0.08,
            'temperate_grassland': 0.09,
            'shrubland': 0.11,
            'cropland': 0.13,
            'tundra': 0.08,
            'desert': 0.14
        }
        
        # LUE_max values (gC/MJ)
        self.lue_max = {
            'tropical_rainforest': 0.389,
            'tropical_savanna': 0.452,
            'temperate_forest': 0.485,
            'boreal_forest': 0.512,
            'temperate_grassland': 0.534,
            'shrubland': 0.498,
            'cropland': 0.608,
            'tundra': 0.421,
            'desert': 0.350
        }
        
        # Total land area: 149 million km²
        self.total_land_area = 149e6  # km²
    
    def load_from_file(self, filepath: str) -> List[Dict]:
        """
        Load MODIS data from CSV file
        
        Parameters
        ----------
        filepath : str
            Path to CSV file
        
        Returns
        -------
        list
            List of NPP 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 MODIS data for testing"""
        data = []
        
        for year in [2000, 2005, 2010, 2015, 2020, 2025]:
            data.append({
                'year': year,
                'npp_global': self.npp_ref[year],
                'npp_uncertainty': 4.2
            })
        
        return data
    
    def get_global_npp(self, year: int) -> float:
        """
        Get global NPP for given year
        
        Parameters
        ----------
        year : int
            Target year
        
        Returns
        -------
        float
            NPP in PgC/yr
        """
        years = sorted(self.npp_ref.keys())
        closest = min(years, key=lambda y: abs(y - year))
        return self.npp_ref[closest]
    
    def get_biome_npp(self, biome: str) -> float:
        """
        Get NPP for specific biome
        
        Parameters
        ----------
        biome : str
            Biome name
        
        Returns
        -------
        float
            NPP in gC/m²/yr
        """
        return self.biome_npp.get(biome, 500)
    
    def get_lue_max(self, biome: str) -> float:
        """
        Get maximum light use efficiency for biome
        
        Parameters
        ----------
        biome : str
            Biome name
        
        Returns
        -------
        float
            LUE_max in gC/MJ
        """
        return self.lue_max.get(biome, 0.5)
    
    def compute_npp_from_lue(self, phi_q: float, fapar: float,
                            lue_max: float, sw_in: float,
                            temperature: float = 25.0,
                            vpd: float = 1.0) -> float:
        """
        Compute NPP using Light Use Efficiency model
        
        NPP = Φ_q · fAPAR · LUE_max · SW_in · f(T) · f(VPD)
        
        Parameters
        ----------
        phi_q : float
            Photosynthetic quantum yield
        fapar : float
            Fraction of absorbed PAR
        lue_max : float
            Maximum light use efficiency (gC/MJ)
        sw_in : float
            Shortwave radiation (W/m²)
        temperature : float
            Temperature (°C)
        vpd : float
            Vapor pressure deficit (kPa)
        
        Returns
        -------
        float
            NPP in gC/m²/day
        """
        # Temperature limitation function
        t_opt = 22.5
        t_width = 15.0
        f_temp = math.exp(-((temperature - t_opt) / t_width) ** 2)
        
        # VPD stress function
        if vpd > 0:
            f_vpd = math.exp(-vpd / 2.5)
        else:
            f_vpd = 1.0
        
        # LUE model
        npp = (phi_q * fapar * lue_max * sw_in * 
               f_temp * f_vpd)
        
        return npp
    
    def get_biome_weights(self) -> Dict[str, float]:
        """
        Get biome weights for global aggregation
        
        Returns
        -------
        dict
            Biome weights (fraction of land area)
        """
        return self.land_cover.copy()
    
    def get_fapar_climatology(self, biome: str, month: int) -> float:
        """
        Get climatological fAPAR for biome and month
        
        Parameters
        ----------
        biome : str
            Biome name
        month : int
            Month (1-12)
        
        Returns
        -------
        float
            fAPAR value (0-1)
        """
        # Simplified fAPAR values by biome
        fapar_by_biome = {
            'tropical_rainforest': 0.85,
            'tropical_savanna': 0.60,
            'temperate_forest': 0.70,
            'boreal_forest': 0.50,
            'temperate_grassland': 0.45,
            'shrubland': 0.35,
            'cropland': 0.65,
            'tundra': 0.30,
            'desert': 0.10
        }
        
        base = fapar_by_biome.get(biome, 0.5)
        
        # Seasonal variation for temperate/boreal
        if biome in ['temperate_forest', 'boreal_forest', 'temperate_grassland', 'cropland']:
            # Northern hemisphere seasonality
            seasonal = 0.2 * math.sin(2 * math.pi * (month - 6) / 12)
            return max(0.1, min(0.95, base + seasonal))
        
        return base
    
    def summary(self) -> str:
        """Print summary of MODIS data"""
        current_npp = self.get_global_npp(2025)
        
        summary = f"""
╔════════════════════════════════════════════════════════════════╗
║                    MODIS NPP Summary                           ║
╠════════════════════════════════════════════════════════════════╣
║  Global NPP (2025): {current_npp:.1f} ± 4.2 PgC/yr                  ║
║  Land area        : {self.total_land_area/1e6:.1f} million km²            ║
╠════════════════════════════════════════════════════════════════╣
║  Biome NPP (gC/m²/yr):                                        ║
║    Tropical rainforest : {self.biome_npp['tropical_rainforest']}                         ║
║    Temperate forest    : {self.biome_npp['temperate_forest']}                         ║
║    Boreal forest       : {self.biome_npp['boreal_forest']}                         ║
║    Cropland           : {self.biome_npp['cropland']}                         ║
║    Tundra             : {self.biome_npp['tundra']}                         ║
╠════════════════════════════════════════════════════════════════╣
║  LUE_max range      : {min(self.lue_max.values()):.3f} - {max(self.lue_max.values()):.3f} gC/MJ   ║
╚════════════════════════════════════════════════════════════════╝
        """
        return summary
