"""Detection filtering pipeline."""

from abc import ABC, abstractmethod
import numpy as np
from typing import List
from eye.detection.core import Detections


class Filter(ABC):
    """Base filter class."""
    
    @abstractmethod
    def __call__(self, detections: Detections) -> Detections:
        """Apply filter to detections."""
        pass


class ConfidenceFilter(Filter):
    """Filter by confidence threshold."""
    
    def __init__(self, min_confidence: float = 0.5):
        self.min_confidence = min_confidence
    
    def __call__(self, detections: Detections) -> Detections:
        if detections.confidence is None or len(detections) == 0:
            return detections
        mask = detections.confidence >= self.min_confidence
        return detections[mask]


class AreaFilter(Filter):
    """Filter by bounding box area."""
    
    def __init__(self, min_area: float = 100, max_area: float = float('inf')):
        self.min_area = min_area
        self.max_area = max_area
    
    def __call__(self, detections: Detections) -> Detections:
        if len(detections) == 0:
            return detections
        areas = detections.area
        mask = (areas >= self.min_area) & (areas <= self.max_area)
        return detections[mask]


class AspectRatioFilter(Filter):
    """Filter by aspect ratio."""
    
    def __init__(self, min_ratio: float = 0.1, max_ratio: float = 10.0):
        self.min_ratio = min_ratio
        self.max_ratio = max_ratio
    
    def __call__(self, detections: Detections) -> Detections:
        if len(detections) == 0:
            return detections
        widths = detections.xyxy[:, 2] - detections.xyxy[:, 0]
        heights = detections.xyxy[:, 3] - detections.xyxy[:, 1]
        ratios = widths / np.maximum(heights, 1e-6)
        mask = (ratios >= self.min_ratio) & (ratios <= self.max_ratio)
        return detections[mask]


class ClassFilter(Filter):
    """Filter by class IDs."""
    
    def __init__(self, allowed_classes: List[int]):
        self.allowed_classes = np.array(allowed_classes)
    
    def __call__(self, detections: Detections) -> Detections:
        if detections.class_id is None or len(detections) == 0:
            return detections
        mask = np.isin(detections.class_id, self.allowed_classes)
        return detections[mask]


class FilterPipeline:
    """Chain multiple filters together.
    
    Innovation: Composable filtering with statistics tracking.
    """
    
    def __init__(self, filters: List[Filter]):
        self.filters = filters
        self.stats = {
            'total_processed': 0,
            'total_filtered': 0,
            'filter_counts': [0] * len(filters)
        }
    
    def __call__(self, detections: Detections) -> Detections:
        """Apply all filters in sequence."""
        self.stats['total_processed'] += len(detections)
        initial_count = len(detections)
        
        for i, filter_obj in enumerate(self.filters):
            before = len(detections)
            detections = filter_obj(detections)
            after = len(detections)
            self.stats['filter_counts'][i] += (before - after)
        
        self.stats['total_filtered'] += (initial_count - len(detections))
        return detections
    
    def get_stats(self) -> dict:
        """Get filtering statistics."""
        return self.stats.copy()
    
    def reset_stats(self):
        """Reset statistics."""
        self.stats = {
            'total_processed': 0,
            'total_filtered': 0,
            'filter_counts': [0] * len(self.filters)
        }
