"""Frame quality scoring for underwater footage.

For each frame, compute:
  - laplacian_var: focus/sharpness (cv2.Laplacian variance)
  - contrast: stddev of grayscale
  - blue_dominance: mean(B - R), positive = water dominant
  - mean_r/g/b: per-channel means

Classification (priority order):
  - mean_r > mean_g + 5 AND mean_r > mean_b + 5 → 'out_of_water'
  - laplacian_var < 50 AND contrast < 25       → 'turbid_water'
  - laplacian_var >= 80 AND contrast >= 35
    AND blue_dominance > -10                   → 'bottom_visible'
  - else                                       → 'water_no_bottom'
"""
from __future__ import annotations

from collections import Counter
from typing import Iterable

import cv2
import numpy as np


def score_frame(frame_bgr: np.ndarray) -> dict:
    """Return per-frame QC metrics + class label."""
    gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY)
    lap_var = float(cv2.Laplacian(gray, cv2.CV_64F).var())
    contrast = float(gray.std())
    b, g, r = cv2.split(frame_bgr)
    mean_r = float(r.mean())
    mean_g = float(g.mean())
    mean_b = float(b.mean())
    blue_dom = float(mean_b - mean_r)

    if mean_r > mean_g + 5 and mean_r > mean_b + 5:
        klass = "out_of_water"
    elif lap_var < 50 and contrast < 25:
        klass = "turbid_water"
    elif lap_var >= 80 and contrast >= 35 and blue_dom > -10:
        klass = "bottom_visible"
    else:
        klass = "water_no_bottom"

    return {
        "laplacian_var": round(lap_var, 2),
        "contrast": round(contrast, 2),
        "blue_dominance": round(blue_dom, 2),
        "mean_r": round(mean_r, 1),
        "mean_g": round(mean_g, 1),
        "mean_b": round(mean_b, 1),
        "class": klass,
        "score_ok": klass == "bottom_visible",
    }


def score_image_file(path) -> dict | None:
    """Load image with OpenCV and score it. Returns None on failure."""
    img = cv2.imread(str(path))
    if img is None:
        return None
    res = score_frame(img)
    res["file"] = str(path)
    return res


def aggregate(scores: Iterable[dict]) -> dict:
    """Aggregate a sequence of score_frame() dicts."""
    scores = list(scores)
    total = len(scores)
    counts = Counter(s["class"] for s in scores)
    bottom = counts.get("bottom_visible", 0)
    return {
        "frames_total": total,
        "frames_bottom_visible": bottom,
        "frames_out_of_water": counts.get("out_of_water", 0),
        "frames_turbid": counts.get("turbid_water", 0),
        "frames_water_no_bottom": counts.get("water_no_bottom", 0),
        "bottom_visible_pct": round(100.0 * bottom / total, 1) if total else 0.0,
    }


CLASS_ORDER = ("bottom_visible", "water_no_bottom", "turbid_water", "out_of_water")
