"""Detection filtering — converts pixel masks into clean bounding box detections."""

import cv2
import numpy as np


def filter_detections(
    crack_mask: np.ndarray,
    crack_prob: np.ndarray,
    min_area: int = 100,
    min_perimeter: int = 40,
    min_density: float = 0.01,
    min_aspect: float = 1.5,
    min_aspect_area: int = 300,
    min_confidence: float = 0.3,
) -> list[dict]:
    """Filter crack contours and return valid detections.

    Filters by area, perimeter, pixel density, elongation, and confidence
    to remove noise and keep only real cracks.

    Returns:
        List of dicts with keys: bbox, confidence, area, density, aspect.
    """
    contours, _ = cv2.findContours(crack_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    detections = []

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area < min_area:
            continue

        perimeter = cv2.arcLength(cnt, True)
        if perimeter < min_perimeter:
            continue

        x, y, w, h = cv2.boundingRect(cnt)
        bbox_area = w * h
        if bbox_area == 0:
            continue

        roi = crack_mask[y:y+h, x:x+w]
        density = np.sum(roi > 0) / bbox_area
        if density < min_density:
            continue

        aspect = max(w, h) / max(min(w, h), 1)
        if aspect < min_aspect and area < min_aspect_area:
            continue

        roi_prob = crack_prob[y:y+h, x:x+w]
        mean_conf = float(np.mean(roi_prob[roi > 0])) if np.any(roi > 0) else 0.0
        if mean_conf < min_confidence:
            continue

        detections.append({
            "bbox": (x, y, w, h),
            "confidence": mean_conf,
            "area": float(area),
            "density": float(density),
            "aspect": float(aspect),
        })

    return detections
