from __future__ import annotations

"""Filter GTA-UAV-LR images by segmentation class coverage.

Reads palette-mode PNG segmentation masks, computes per-class pixel ratios,
and outputs a JSON meta file listing images that pass the filter
(i.e. background + water < threshold).

Classes (from manifest.json):
    0: background, 1: building, 2: road, 3: vegetation, 4: water, ...

Usage:
    python -m scripts.filter_segmentation [--threshold 0.9] [--output meta/seg_filter.json]
"""

import argparse
import json
import logging
from pathlib import Path

import coloredlogs
import numpy as np
from PIL import Image
from tqdm import tqdm

LOGGER = logging.getLogger("caption_test.filter_seg")

SEGM_ROOT = Path("/home/servml/Документы/datasets/GTA-UAV-LR-aug/segm")
EXCLUDE_CLASSES = {0, 4}  # background, water
DEFAULT_THRESHOLD = 0.90


def compute_class_ratios(mask_path: Path) -> dict[int, float]:
    """Load a palette-mode PNG mask and return per-class pixel ratios."""
    with Image.open(mask_path) as img:
        arr = np.array(img)
    total = arr.size
    unique, counts = np.unique(arr, return_counts=True)
    return {int(cls): float(cnt / total) for cls, cnt in zip(unique, counts)}


def scan_masks(
    segm_root: Path,
    exclude_classes: set[int],
    threshold: float,
) -> dict[str, dict]:
    """Scan all segmentation masks and classify as pass/fail.

    Returns:
        Dict keyed by relative image name (e.g. "drone/images/100_0001_0000000000.png")
        with values: {"ratios": {...}, "excluded_ratio": float, "pass": bool}
    """
    results: dict[str, dict] = {}
    subdirs = sorted(p for p in segm_root.iterdir() if p.is_dir())

    for subdir in subdirs:
        mask_files = sorted(subdir.rglob("*.png"))
        LOGGER.info("🔍 Scanning %s: %d masks", subdir.name, len(mask_files))

        for mask_path in tqdm(mask_files, desc=f"  📂 {subdir.name}", unit="img", leave=False):
            rel = mask_path.relative_to(segm_root)
            ratios = compute_class_ratios(mask_path)
            excluded_ratio = sum(ratios.get(c, 0.0) for c in exclude_classes)
            results[str(rel)] = {
                "ratios": ratios,
                "excluded_ratio": round(excluded_ratio, 6),
                "pass": excluded_ratio < threshold,
            }

    return results


def build_meta(
    results: dict[str, dict],
) -> dict[str, list[str]]:
    """Split results into passed and excluded lists."""
    passed = sorted(k for k, v in results.items() if v["pass"])
    excluded = sorted(k for k, v in results.items() if not v["pass"])
    return {"passed": passed, "excluded": excluded}


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Filter GTA-UAV-LR images by segmentation coverage.",
    )
    parser.add_argument(
        "--segm-root", type=str, default=str(SEGM_ROOT),
        help="Root of segmentation masks.",
    )
    parser.add_argument(
        "--threshold", type=float, default=DEFAULT_THRESHOLD,
        help="Exclude images where background+water >= threshold.",
    )
    parser.add_argument(
        "--output", type=str, default="meta/seg_filter.json",
        help="Output JSON meta file path.",
    )
    args = parser.parse_args()

    coloredlogs.install(
        level="INFO",
        logger=LOGGER,
        fmt="%(asctime)s %(name)s %(levelname)s %(message)s",
    )

    LOGGER.info("🚀 Starting segmentation filter (threshold=%.2f)", args.threshold)

    segm_root = Path(args.segm_root)
    results = scan_masks(segm_root, EXCLUDE_CLASSES, args.threshold)
    meta = build_meta(results)

    n_total = len(results)
    n_pass = len(meta["passed"])
    n_excl = len(meta["excluded"])
    LOGGER.info(
        "📊 total=%d  ✅ passed=%d (%.1f%%)  ❌ excluded=%d (%.1f%%)",
        n_total, n_pass, 100 * n_pass / max(n_total, 1),
        n_excl, 100 * n_excl / max(n_total, 1),
    )

    output_path = Path(args.output)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    out = {
        "threshold": args.threshold,
        "exclude_classes": sorted(EXCLUDE_CLASSES),
        "total_images": n_total,
        "passed_count": n_pass,
        "excluded_count": n_excl,
        "passed": meta["passed"],
        "excluded": meta["excluded"],
    }
    with output_path.open("w", encoding="utf-8") as f:
        json.dump(out, f, indent=2)

    LOGGER.info("💾 Meta file saved to %s", output_path)


if __name__ == "__main__":
    main()
