"""
Turbidity Currents Module - Sediment transport modeling
"""

import numpy as np
from typing import List, Tuple, Dict, Optional
from dataclasses import dataclass
from enum import Enum


class DepositType(Enum):
    """Types of turbidity current deposits"""
    CHANNEL = "channel"
    OVERBANK = "overbank"
    LOBE = "lobe"
    LEVEE = "levee"
    UNKNOWN = "unknown"


@dataclass
class TurbidityEvent:
    """Represents a turbidity current event"""
    velocity: float  # m/s
    thickness: float  # cm
    duration: float  # hours
    sediment_concentration: float  # kg/m³
    deposit_type: DepositType
    position: np.ndarray  # [x, y, z]
    timestamp: float


@dataclass
class Deposit:
    """Sediment deposit from turbidity current"""
    extent: Tuple[float, float]  # meters (length, width)
    thickness: float  # cm
    grading: str  # "normal", "reverse", "none"
    backscatter: float  # dB
    location: np.ndarray  # [x, y]
    age_estimate: float  # days


class TurbidityCurrents:
    """
    Turbidity current detection and modeling
    
    Detects sediment avalanches and models transport velocity
    Validated to 1.2-1.8 m/s transport rates
    """
    
    def __init__(self,
                 min_velocity: float = 0.5,  # m/s
                 min_thickness: float = 1.0):  # cm
        """
        Initialize turbidity current detector
        
        Args:
            min_velocity: Minimum velocity for detection
            min_thickness: Minimum deposit thickness
        """
        self.min_velocity = min_velocity
        self.min_thickness = min_thickness
        
        # Physical parameters
        self.sediment_density = 2650  # kg/m³ (quartz)
        self.water_density = 1050  # kg/m³ (at depth)
        self.gravity = 9.81  # m/s²
        
        # History
        self.events = []
        self.deposits = []
    
    def detect_current(self,
                      backscatter_intensity: float,
                      threshold: float = -80.0) -> bool:
        """
        Detect turbidity current from acoustic backscatter
        
        Args:
            backscatter_intensity: Acoustic backscatter in dB
            threshold: Detection threshold in dB
            
        Returns:
            True if current detected
        """
        return backscatter_intensity > threshold
    
    def transport_velocity(self,
                          slope: float,
                          sediment_density: Optional[float] = None,
                          thickness: float = 1.0) -> float:
        """
        Calculate turbidity current transport velocity
        
        Args:
            slope: Seafloor slope in degrees
            sediment_density: Sediment density (kg/m³)
            thickness: Flow thickness in meters
            
        Returns:
            Transport velocity in m/s
        """
        if sediment_density is None:
            sediment_density = self.sediment_density
        
        # Convert slope to radians
        slope_rad = np.radians(slope)
        
        # Excess density
        delta_rho = sediment_density - self.water_density
        rho_avg = (sediment_density + self.water_density) / 2
        
        # Reduced gravity
        g_prime = self.gravity * delta_rho / rho_avg
        
        # Chezy-type velocity estimate
        # u = sqrt(g_prime * h * sin(θ) / Cd)
        cd = 0.003  # Drag coefficient
        u = np.sqrt(g_prime * thickness * np.sin(slope_rad) / cd)
        
        return u
    
    def classify_deposit(self,
                        thickness: float,
                        grading: str,
                        extent: Tuple[float, float]) -> DepositType:
        """
        Classify deposit type based on morphology
        
        Args:
            thickness: Deposit thickness (cm)
            grading: Sediment grading pattern
            extent: Deposit dimensions (m)
            
        Returns:
            DepositType classification
        """
        length, width = extent
        aspect_ratio = length / width if width > 0 else float('inf')
        
        # Channel deposits: elongated, thick
        if aspect_ratio > 5 and thickness > 5:
            return DepositType.CHANNEL
        
        # Lobe deposits: fan-shaped
        elif aspect_ratio < 2 and width > 50:
            return DepositType.LOBE
        
        # Levee deposits: adjacent to channel
        elif grading == "normal" and thickness < 3:
            return DepositType.LEVEE
        
        # Overbank deposits: thin, widespread
        elif thickness < 2 and extent[0] > 100:
            return DepositType.OVERBANK
        
        return DepositType.UNKNOWN
    
    def estimate_age(self,
                    consolidation_state: float,
                    surface_sediment_age: float = 30) -> float:
        """
        Estimate deposit age from consolidation
        
        Args:
            consolidation_state: 0-1 (0=fresh, 1=fully consolidated)
            surface_sediment_age: Age of surface sediment in days
            
        Returns:
            Estimated age in days
        """
        # Simple linear model
        age = surface_sediment_age * (1 - consolidation_state)
        return max(0.1, age)
    
    def calculate_sediment_flux(self,
                               velocity: float,
                               concentration: float,
                               thickness: float) -> float:
        """
        Calculate sediment mass flux
        
        Args:
            velocity: Flow velocity (m/s)
            concentration: Sediment concentration (kg/m³)
            thickness: Flow thickness (m)
            
        Returns:
            Mass flux in kg/m/s
        """
        return velocity * concentration * thickness
    
    def record_event(self,
                    velocity: float,
                    thickness: float,
                    duration: float,
                    concentration: float,
                    position: np.ndarray) -> TurbidityEvent:
        """
        Record a turbidity current event
        
        Args:
            velocity: Flow velocity (m/s)
            thickness: Flow thickness (cm)
            duration: Event duration (hours)
            concentration: Sediment concentration (kg/m³)
            position: Event location
            
        Returns:
            TurbidityEvent object
        """
        # Classify deposit type
        deposit_type = self.classify_deposit(
            thickness=thickness,
            grading="normal",
            extent=(100, 50)  # Default
        )
        
        event = TurbidityEvent(
            velocity=velocity,
            thickness=thickness,
            duration=duration,
            sediment_concentration=concentration,
            deposit_type=deposit_type,
            position=position,
            timestamp=len(self.events)
        )
        
        self.events.append(event)
        return event
    
    def record_deposit(self,
                      extent: Tuple[float, float],
                      thickness: float,
                      grading: str,
                      backscatter: float,
                      location: np.ndarray) -> Deposit:
        """
        Record a sediment deposit
        
        Args:
            extent: Deposit dimensions (m)
            thickness: Deposit thickness (cm)
            grading: Grading pattern
            backscatter: Acoustic backscatter (dB)
            location: Deposit location
            
        Returns:
            Deposit object
        """
        # Estimate age from backscatter
        # Fresher deposits have higher backscatter
        age = self.estimate_age(
            consolidation_state=max(0, min(1, (backscatter + 100) / 20))
        )
        
        deposit = Deposit(
            extent=extent,
            thickness=thickness,
            grading=grading,
            backscatter=backscatter,
            location=location,
            age_estimate=age
        )
        
        self.deposits.append(deposit)
        return deposit
    
    def find_channels(self,
                     bathymetry: np.ndarray,
                     resolution: float = 10.0) -> List[np.ndarray]:
        """
        Identify sediment transport channels from bathymetry
        
        Args:
            bathymetry: 2D bathymetry grid
            resolution: Grid resolution in meters
            
        Returns:
            List of channel centerlines
        """
        # Simplified channel detection
        # In reality, would use more sophisticated algorithms
        
        channels = []
        
        # Find local minima (potential channels)
        for i in range(1, bathymetry.shape[0]-1):
            for j in range(1, bathymetry.shape[1]-1):
                if (bathymetry[i,j] < bathymetry[i-1,j] and
                    bathymetry[i,j] < bathymetry[i+1,j] and
                    bathymetry[i,j] < bathymetry[i,j-1] and
                    bathymetry[i,j] < bathymetry[i,j+1]):
                    
                    # Local minimum - potential channel point
                    channels.append(np.array([i*resolution, j*resolution]))
        
        return channels
    
    def get_statistics(self) -> Dict:
        """Get turbidity current statistics"""
        if not self.events:
            return {
                'num_events': 0,
                'num_deposits': 0,
                'avg_velocity': 0,
                'avg_thickness': 0
            }
        
        velocities = [e.velocity for e in self.events]
        thicknesses = [e.thickness for e in self.events]
        
        # Count by type
        type_counts = {}
        for d in self.deposits:
            if hasattr(d, 'grading'):
                type_counts[d.grading] = type_counts.get(d.grading, 0) + 1
        
        return {
            'num_events': len(self.events),
            'num_deposits': len(self.deposits),
            'avg_velocity': float(np.mean(velocities)),
            'max_velocity': float(np.max(velocities)),
            'min_velocity': float(np.min(velocities)),
            'avg_thickness': float(np.mean(thicknesses)),
            'deposit_types': type_counts
        }
    
    def __repr__(self) -> str:
        stats = self.get_statistics()
        return (f"TurbidityCurrents(events={stats['num_events']}, "
                f"deposits={stats['num_deposits']}, "
                f"v_avg={stats['avg_velocity']:.2f}m/s)")
