from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any

from PIL import Image


def _detections_to_coco(
    detections: Any,  # supervision.Detections
    image_path: Path,
    image_id: int,
    category_id: int = 0,  # Assuming single class 'knot'
) -> dict[str, Any]:
    """Convert supervision.Detections to COCO annotation format for one image."""
    annotations = []
    for i in range(len(detections)):
        xyxy = detections.xyxy[i].tolist()
        conf = float(detections.confidence[i]) if detections.confidence is not None else 1.0
        # COCO bbox: [x_min, y_min, width, height]
        x_min, y_min, x_max, y_max = xyxy
        width = x_max - x_min
        height = y_max - y_min
        bbox = [x_min, y_min, width, height]

        ann = {
            "id": image_id * 1000 + i,  # Simple ID scheme
            "image_id": image_id,
            "category_id": category_id,
            "bbox": bbox,
            "area": width * height,
            "iscrowd": 0,
            "score": conf,  # Optional, for model confidence
        }
        annotations.append(ann)

    return {"annotations": annotations}


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Auto-label new images with trained RF-DETR, output COCO JSON."
    )
    parser.add_argument("--weights", type=Path, required=True, help="Path to trained checkpoint")
    parser.add_argument("--images-dir", type=Path, required=True, help="Directory with new images")
    parser.add_argument("--output-json", type=Path, required=True, help="Output COCO JSON file")
    parser.add_argument("--threshold", type=float, default=0.5)
    parser.add_argument("--category-name", default="knot", help="Class name for annotations")
    args = parser.parse_args()

    if not args.weights.exists():
        raise SystemExit(f"Weights not found: {args.weights}")
    if not args.images_dir.exists():
        raise SystemExit(f"Images dir not found: {args.images_dir}")

    from rfdetr import RFDETRBase

    model = RFDETRBase(pretrain_weights=str(args.weights))

    # Collect all images
    image_paths = list(args.images_dir.glob("*.jpg")) + list(args.images_dir.glob("*.png"))
    if not image_paths:
        raise SystemExit(f"No .jpg or .png images found in {args.images_dir}")

    coco_data = {
        "images": [],
        "annotations": [],
        "categories": [{"id": 0, "name": args.category_name, "supercategory": "none"}],
    }

    ann_id_counter = 0
    for img_id, img_path in enumerate(sorted(image_paths)):
        image = Image.open(img_path).convert("RGB")
        detections = model.predict(image, threshold=args.threshold)

        # Add image entry
        width, height = image.size
        coco_data["images"].append({
            "id": img_id,
            "file_name": img_path.name,
            "width": width,
            "height": height,
        })

        # Convert detections to annotations
        ann_data = _detections_to_coco(detections, img_path, img_id, category_id=0)
        for ann in ann_data["annotations"]:
            ann["id"] = ann_id_counter
            ann_id_counter += 1
            coco_data["annotations"].append(ann)

    # Write COCO JSON
    with args.output_json.open("w", encoding="utf-8") as f:
        json.dump(coco_data, f, indent=2)

    print(f"Auto-labeled {len(image_paths)} images -> {args.output_json}")
    print(f"Total annotations: {len(coco_data['annotations'])}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
