"""
Response and configuration models for the AEY Vision SDK.
"""
from dataclasses import dataclass, field, asdict
from typing import List, Dict, Any, Optional


@dataclass
class MetaData:
    """Video metadata from analysis."""
    total_frames: int
    fps: float
    duration: float
    processing_time: float


@dataclass
class Timing:
    """Processing timing information."""
    processing_time: float
    gpu_seconds: float


@dataclass
class Billing:
    """Billing information for the analysis."""
    tokens_used: int
    gpu_seconds: float
    tokens_per_gpu_second: int


@dataclass
class AnalysisResult:
    """
    Unified result object containing both analysis data and optional video output.
    
    Attributes:
        meta: Video metadata
        analyzers: Analysis results by feature type
        timing: Processing timing information
        billing: Billing information (optional)
        video_bytes: Annotated video content (optional)
        video_path: Original input video path (optional, for default filename)
    """
    meta: MetaData
    analyzers: Dict[str, Any]
    timing: Timing
    billing: Optional[Billing] = None
    video_bytes: Optional[bytes] = None
    video_path: Optional[str] = None
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any], video_bytes: Optional[bytes] = None, video_path: Optional[str] = None) -> 'AnalysisResult':
        """Create AnalysisResult from API response dictionary."""
        billing = None
        if 'billing' in data:
            billing = Billing(**data['billing'])
        
        return cls(
            meta=MetaData(**data['meta']),
            analyzers=data['analyzers'],
            timing=Timing(**data['timing']),
            billing=billing,
            video_bytes=video_bytes,
            video_path=video_path
        )
    
    def dict(self) -> Dict[str, Any]:
        """Convert to dictionary for backward compatibility."""
        result = {
            'meta': asdict(self.meta),
            'analyzers': self.analyzers,
            'timing': asdict(self.timing)
        }
        if self.billing:
            result['billing'] = asdict(self.billing)
        return result
        
    def save(self, filename: Optional[str] = None) -> str:
        """
        Save the annotated video to a file.
        
        Args:
            filename: Output filename. If None, generates one based on input filename.
            
        Returns:
            Path to the saved file.
            
        Raises:
            ValueError: If no video data is available.
        """
        if not self.video_bytes:
            raise ValueError("No video data available. Did you call .with_annotated_video(True)?")
            
        if not filename:
            if self.video_path:
                import os
                base, ext = os.path.splitext(self.video_path)
                filename = f"{base}_output{ext}"
            else:
                filename = "output.mp4"
                
        with open(filename, "wb") as f:
            f.write(self.video_bytes)
            
        return filename

    def __getitem__(self, key: str) -> Any:
        """Allow dictionary-style access for backward compatibility."""
        if key == 'meta':
            return asdict(self.meta)
        elif key == 'analyzers':
            return self.analyzers
        elif key == 'timing':
            return asdict(self.timing)
        elif key == 'billing':
            return asdict(self.billing) if self.billing else None
        elif key == 'video':
            return self.video_bytes
        raise KeyError(key)


@dataclass
class AnalysisResponse:
    """
    Legacy response wrapper.
    DEPRECATED: Use AnalysisResult instead.
    """
    meta: MetaData
    analyzers: Dict[str, Any]
    timing: Timing
    billing: Optional[Billing] = None
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'AnalysisResponse':
        return cls(
            meta=MetaData(**data['meta']),
            analyzers=data['analyzers'],
            timing=Timing(**data['timing']),
            billing=Billing(**data['billing']) if 'billing' in data else None
        )
    
    def dict(self) -> Dict[str, Any]:
        result = {
            'meta': asdict(self.meta),
            'analyzers': self.analyzers,
            'timing': asdict(self.timing)
        }
        if self.billing:
            result['billing'] = asdict(self.billing)
        return result


@dataclass
class Zone:
    """Zone definition for spatial analysis."""
    name: str
    points: List[List[float]]
    color: Optional[List[int]] = None
    classes: Optional[List[str]] = None
    
    def dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        result = {'name': self.name, 'points': self.points}
        if self.color:
            result['color'] = self.color
        if self.classes:
            result['classes'] = self.classes
        return result


@dataclass
class Line:
    """Line definition for entry/exit counting."""
    name: str
    points: List[List[float]]
    
    def dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {'name': self.name, 'points': self.points}


# Configuration classes
@dataclass
class RegionCounterConfig:
    """Configuration for region counter analysis."""
    type: str = "region_counter"
    model: Optional[str] = None
    classes: Optional[List[str]] = None
    confidence: float = 0.5
    zones: Optional[List[Dict[str, Any]]] = None
    immediate_return: bool = False
    require_movement: bool = False
    movement_sensitivity: float = 0.1
    tracking_duration: int = 30


@dataclass
class PPEConfig:
    """Configuration for PPE detection."""
    type: str = "ppe"
    model_path: Optional[str] = None
    confidence: float = 0.5
    required_ppe: Optional[List[str]] = None


@dataclass
class RedactionConfig:
    """Configuration for video redaction."""
    type: str = "redaction"
    backend: str = "opencv"
    blur_kernel_size: List[int] = field(default_factory=lambda: [99, 99])
    classes: Optional[List[str]] = None
    fps: int = 30


@dataclass
class ALPRConfig:
    """Configuration for license plate recognition."""
    type: str = "alpr"
    confidence: float = 0.5


@dataclass
class AgeEmotionConfig:
    """Configuration for age and emotion detection."""
    type: str = "age_emotion"
    backend: Optional[str] = None
    person_model: Optional[str] = None
    fps: int = 30
    min_face_size: Optional[int] = None


@dataclass
class TimeInRegionConfig:
    """Configuration for time in region analysis."""
    type: str = "time_in_region"
    model: Optional[str] = None
    fps: int = 30
    zones: Optional[List[Dict[str, Any]]] = None


@dataclass
class EntryExitConfig:
    """Configuration for entry/exit counting."""
    type: str = "entry_exit"
    model: Optional[str] = None
    classes: Optional[List[str]] = None
    zones: Optional[List[Dict[str, Any]]] = None
    lines: Optional[List[Dict[str, Any]]] = None


@dataclass
class FallDetectionConfig:
    """Configuration for fall detection."""
    type: str = "fall_detection"
    angle_threshold: float = 45.0
    aspect_ratio_threshold: float = 1.5
    confidence: float = 0.5
