"""
Data models for uniWeather API
"""

from dataclasses import dataclass
from typing import List, Optional, Dict, Any
from datetime import datetime


@dataclass
class DeviceInfo:
    """Information about a device"""
    device_id: str
    status: Optional[str] = None
    station_name: Optional[str] = None
    location_latitude: Optional[float] = None
    location_longitude: Optional[float] = None
    provider_name: Optional[str] = None
    project_name: Optional[str] = None
    city_name: Optional[str] = None
    first_seen: Optional[datetime] = None
    last_seen: Optional[datetime] = None
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'DeviceInfo':
        """Create DeviceInfo from API response dict"""
        first_seen = None
        last_seen = None
        
        if 'firstSeen' in data:
            first_seen = datetime.fromisoformat(data['firstSeen'].replace('Z', '+00:00'))
        if 'lastSeen' in data:
            last_seen = datetime.fromisoformat(data['lastSeen'].replace('Z', '+00:00'))
        
        return cls(
            device_id=data['deviceID'],
            status=data.get('status'),
            station_name=data.get('stationName'),
            location_latitude=data.get('locationLatitude'),
            location_longitude=data.get('locationLongitude'),
            provider_name=data.get('providerName'),
            project_name=data.get('projectName'),
            city_name=data.get('cityName'),
            first_seen=first_seen,
            last_seen=last_seen
        )


@dataclass
class Device:
    """Represents a device with its channels"""
    device_id: str
    channels: Optional[List[str]] = None
    info: Optional[DeviceInfo] = None
    
    @property
    def name(self) -> str:
        """Get device name (station_name or device_id)"""
        if self.info and self.info.station_name:
            return self.info.station_name
        return self.device_id


@dataclass
class DataQueryResponse:
    """Response from a data query - wraps CSV data as pandas DataFrame"""
    device_id: str
    start_time: float
    end_time: float
    channels: List[str]
    _dataframe: Any
    
    @classmethod
    def from_csv(cls, csv_text: str, device_id: str) -> 'DataQueryResponse':
        """
        Create DataQueryResponse from CSV text with time-aligned aggregation
        
        Aligns sparse sensor readings within measurement cycles (typically ~30s windows)
        into consolidated rows, forward-filling values within each cycle.
        
        Args:
            csv_text: CSV data from the API
            device_id: Device ID for this data
            
        Returns:
            DataQueryResponse with aligned DataFrame
        """
        try:
            import pandas as pd
            from io import StringIO
        except ImportError:
            raise ImportError(
                "pandas is required for data queries. "
                "Install it with: pip install pandas"
            )
        
        # Parse CSV directly into DataFrame
        if not csv_text.strip():
            df = pd.DataFrame()
        else:
            df = pd.read_csv(StringIO(csv_text), parse_dates=['timestamp'])
            if not df.empty and 'timestamp' in df.columns:
                df.set_index('timestamp', inplace=True)
        
        # Extract channel names and time range
        channel_names = list(df.columns) if not df.empty else []
        
        if not df.empty and len(df) > 0:
            # Align measurements to time windows by grouping into 1-minute intervals
            # For each channel, take the last non-NaN value within each minute
            # This consolidates sensor readings from the same measurement cycle
            df_aligned = df.resample('1min').apply(lambda x: x.dropna().iloc[-1] if not x.dropna().empty else pd.NA)
            
            # Remove rows that are entirely NaN (no data in that minute)
            df_aligned = df_aligned.dropna(how='all')
            
            start_time = df_aligned.index.min().timestamp()
            end_time = df_aligned.index.max().timestamp()
        else:
            df_aligned = df
            start_time = 0.0
            end_time = 0.0
        
        return cls(
            device_id=device_id,
            start_time=start_time,
            end_time=end_time,
            channels=channel_names,
            _dataframe=df_aligned
        )
    
    def to_dataframe(self):
        """
        Get data as pandas DataFrame
        
        Returns:
            pandas.DataFrame with timestamp index and channel columns
        """
        return self._dataframe

