import json
import requests
from typing import List, Dict, Union, Optional, Any
from dataclasses import dataclass, asdict

@dataclass
class Zone:
    name: str
    points: List[List[float]]

@dataclass
class RegionCounterConfig:
    type: str = "region_counter"
    model: str = "yolo11n.pt"
    classes: Optional[List[str]] = None
    confidence: float = 0.5
    zones: Optional[List[Dict[str, Any]]] = None

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

@dataclass
class RedactionConfig:
    type: str = "redaction"
    backend: str = "opencv"
    blur_kernel_size: List[int] = None

    def __post_init__(self):
        if self.blur_kernel_size is None:
            self.blur_kernel_size = [99, 99]

class AeyVision:
    def __init__(self, api_key: str, base_url: str = "https://api.aeyvision.com"):
        self.api_key = api_key
        self.base_url = base_url.rstrip('/')

    def analyze(self, video_path: str, config: List[Union[Dict, Any]], return_annotated: bool = False) -> Union[Dict, bytes]:
        """
        Analyze a video using the Aey Vision API.

        Args:
            video_path: Path to the video file.
            config: List of configuration objects or dictionaries.
            return_annotated: Whether to return the annotated video as bytes.

        Returns:
            JSON response dictionary or bytes if return_annotated is True.
        """
        
        # Prepare config
        config_data = []
        for c in config:
            if hasattr(c, '__dict__'):
                # Handle dataclasses or objects
                if hasattr(c, 'to_dict'):
                    config_data.append(c.to_dict())
                else:
                    # Simple dataclass to dict
                    config_data.append(asdict(c))
            else:
                config_data.append(c)

        files = {
            'video': ('video.mp4', open(video_path, 'rb'), 'video/mp4'),
        }
        
        data = {
            'config': json.dumps(config_data),
        }
        
        if return_annotated:
            data['return_annotated'] = 'true'

        headers = {
            'X-API-Key': self.api_key,
            # 'Origin': 'http://localhost:3000' # Uncomment for local testing if needed
        }
        
        # If testing locally against localhost, we might need to add Origin header
        if 'localhost' in self.base_url or '127.0.0.1' in self.base_url:
             headers['Origin'] = 'http://localhost:3000'

        response = requests.post(
            f"{self.base_url}/api/v1/analyze",
            headers=headers,
            files=files,
            data=data
        )

        if not response.ok:
            raise Exception(f"Analysis failed: {response.status_code} {response.text}")

        if return_annotated:
            return response.content
        else:
            return response.json()

    def multi_feature_analysis(self, video_path: str, features: List[Union[Dict, Any]], return_annotated: bool = False) -> Union[Dict, bytes]:
        """
        Multi-Feature Analysis - Run multiple analyzers on a single video.
        
        Combine multiple analysis features in one pass for comprehensive insights.
        Save 25% on token costs when using 2+ features together!
        
        Args:
            video_path: Path to the video file.
            features: List of feature configuration objects or dictionaries.
            return_annotated: Whether to return the annotated video as bytes.
        
        Returns:
            JSON response dictionary or bytes if return_annotated is True.
        
        Example:
            >>> # Security monitoring: Movement + PPE + Fall Detection
            >>> sdk = AeyVision(api_key='your-api-key')
            >>> result = sdk.multi_feature_analysis(
            ...     'security-footage.mp4',
            ...     features=[
            ...         {
            ...             'type': 'region_counter',
            ...             'zones': [{'name': 'entrance', 'points': [[0.1,0.1], [0.9,0.1], [0.9,0.9], [0.1,0.9]]}],
            ...             'classes': ['person']
            ...         },
            ...         {
            ...             'type': 'ppe',
            ...             'required_ppe': ['hardhat', 'safety_vest']
            ...         },
            ...         {
            ...             'type': 'fall_detection',
            ...             'confidence': 0.6
            ...         }
            ...     ]
            ... )
            >>> print(result['analyzers'])
        """
        if not features or len(features) < 1:
            raise ValueError('Multi-feature analysis requires at least one feature configuration')
        
        return self.analyze(video_path, features, return_annotated)
