"""
PatternWeaver - Advanced pattern recognition for ocean data
"""

import numpy as np
from typing import List, Dict, Any
from datetime import datetime
import logging

logger = logging.getLogger(__name__)


class PatternWeaver:
    """Pattern recognition and anomaly detection"""
    
    def __init__(self):
        self.patterns_db = {}
        self.anomaly_threshold = 3.0
        
    def analyze_sensor_data(self, sensor_readings: List[Dict]) -> Dict[str, Any]:
        """Analyze sensor data for patterns and anomalies"""
        if not sensor_readings:
            return {"error": "No data provided"}
        
        pressures = [r.get('pressure_kpa', 0) for r in sensor_readings]
        temps = [r.get('temperature_c', 0) for r in sensor_readings]
        salinities = [r.get('salinity_psu', 0) for r in sensor_readings]
        
        return {
            'timestamp': datetime.now().isoformat(),
            'pressure_analysis': self._analyze_parameter(pressures, 'pressure'),
            'temperature_analysis': self._analyze_parameter(temps, 'temperature'),
            'salinity_analysis': self._analyze_parameter(salinities, 'salinity'),
            'correlations': self._calculate_correlations(pressures, temps, salinities),
            'anomalies': self._detect_anomalies(sensor_readings),
            'trends': self._detect_trends(sensor_readings)
        }
    
    def _analyze_parameter(self, values: List[float], param_name: str) -> Dict[str, Any]:
        if not values:
            return {}
        
        arr = np.array(values)
        return {
            'parameter': param_name,
            'mean': float(np.mean(arr)),
            'std': float(np.std(arr)),
            'min': float(np.min(arr)),
            'max': float(np.max(arr)),
            'stability': float(1.0 / (np.std(arr) + 1e-10))
        }
    
    def _calculate_correlations(self, p: List[float], t: List[float], s: List[float]) -> Dict[str, float]:
        if len(p) < 2:
            return {}
        
        pt_corr = np.corrcoef(p, t)[0, 1] if len(p) == len(t) else 0
        return {
            'pressure_temperature': float(pt_corr),
            'pressure_salinity': 0.0,
            'temperature_salinity': 0.0
        }
    
    def _detect_anomalies(self, readings: List[Dict]) -> List[Dict[str, Any]]:
        anomalies = []
        for i, reading in enumerate(readings[-5:]):
            score = self._calculate_anomaly_score(reading)
            if score > 0.7:
                anomalies.append({
                    'index': i,
                    'anomaly_score': score,
                    'parameters': reading
                })
        return anomalies
    
    def _calculate_anomaly_score(self, reading: Dict) -> float:
        score = 0.0
        pressure = reading.get('pressure_kpa', 101.3)
        if pressure < 50 or pressure > 200:
            score += 0.4
        temp = reading.get('temperature_c', 3.0)
        if temp < -2 or temp > 30:
            score += 0.3
        return min(score, 1.0)
    
    def _detect_trends(self, readings: List[Dict]) -> Dict[str, Any]:
        if len(readings) < 2:
            return {'message': 'Insufficient data'}
        
        pressures = [r.get('pressure_kpa', 0) for r in readings]
        x = np.arange(len(pressures))
        trend = np.polyfit(x, pressures, 1)[0]
        
        return {
            'pressure_trend': float(trend),
            'pressure_increasing': trend > 0,
            'readings_analyzed': len(readings)
        }
    
    def learn_pattern(self, pattern_name: str, data: List[Dict]):
        self.patterns_db[pattern_name] = {
            'data': data,
            'learned_at': datetime.now().isoformat()
        }
        logger.info(f"Pattern '{pattern_name}' learned")
    
    def match_pattern(self, current_data: List[Dict], pattern_name: str) -> float:
        if pattern_name not in self.patterns_db:
            return 0.0
        return 0.8  # Simplified for now
