# pylint: disable=import-outside-toplevel,unused-argument

"""Debug visualizer for annotating frames with detection results."""

import logging
import os
from typing import Dict
import cv2

logger = logging.getLogger(__name__)


class DebugVisualizer:
    """
    Visualize detection results on frames for debugging.

    Supports:
    - Person detection (bounding boxes)
    - Object detection (bounding boxes with labels)
    - Brand detection (bounding boxes with brand names)
    """

    COLORS = {
        "person": (0, 255, 0),  # Green
        "object": (255, 0, 0),  # Blue
        "brand": (0, 0, 255),  # Red
        "default": (255, 255, 0),  # Cyan
    }

    @staticmethod
    def visualize_detections(
        frames_dir: str, results: Dict[str, "ProcessorResult"], output_dir: str
    ) -> Dict[str, int]:
        """
        Visualize detection results on frames.

        Args:
            frames_dir: Directory containing extracted frames
            results: Dict of processor results (from PipelineResult.results)
            output_dir: Directory to save annotated frames

        Returns:
            Dict with statistics about visualizations created
        """
        if not os.path.exists(frames_dir):
            logger.warning(f"Frames directory not found: {frames_dir}")
            return {"annotated_frames": 0}

        # Create annotated_frames subdirectory
        annotated_dir = os.path.join(output_dir, "annotated_frames")
        os.makedirs(annotated_dir, exist_ok=True)

        stats = {
            "annotated_frames": 0,
            "person_detections": 0,
            "object_detections": 0,
            "brand_detections": 0,
        }

        frame_files = sorted(
            [
                f
                for f in os.listdir(frames_dir)
                if f.startswith("frame") and f.endswith((".png", ".jpg", ".jpeg"))
            ]
        )

        logger.info(f"Visualizing detections on {len(frame_files)} frames")

        for frame_file in frame_files:
            frame_path = os.path.join(frames_dir, frame_file)
            frame = cv2.imread(frame_path)

            if frame is None:
                logger.warning(f"Could not read frame: {frame_path}")
                continue

            frame_name = frame_file.split(".")[0]
            if "_" in frame_name:
                frame_idx = int(frame_name.split("_")[1])
            else:
                frame_idx = int(frame_name.replace("frame", ""))

            annotated = False

            if "person_detection" in results and results["person_detection"].success:
                person_result = results["person_detection"]
                if DebugVisualizer._annotate_person_detections(frame, person_result, frame_idx):
                    annotated = True
                    stats["person_detections"] += 1

            if "object_detection" in results and results["object_detection"].success:
                object_result = results["object_detection"]
                if DebugVisualizer._annotate_object_detections(frame, object_result, frame_idx):
                    annotated = True
                    stats["object_detections"] += 1

            if "brand_detection" in results and results["brand_detection"].success:
                brand_result = results["brand_detection"]
                if DebugVisualizer._annotate_brand_detections(frame, brand_result, frame_idx):
                    annotated = True
                    stats["brand_detections"] += 1

            if annotated:
                output_path = os.path.join(annotated_dir, f"annotated_{frame_file}")
                cv2.imwrite(output_path, frame)
                stats["annotated_frames"] += 1

        logger.info(
            f"Debug visualization complete: {stats['annotated_frames']} frames annotated "
            f"({stats['person_detections']} person, {stats['object_detections']} object, "
            f"{stats['brand_detections']} brand)"
        )

        return stats

    @staticmethod
    def _annotate_person_detections(
        frame, person_result: "ProcessorResult", frame_idx: int
    ) -> bool:
        """
        Annotate frame with person detection bounding boxes.

        Returns:
            True if annotations were added, False otherwise
        """
        if not person_result.segments:
            return False

        annotated = False
        for segment in person_result.segments:
            if segment.metadata.get("frame_index") == frame_idx:
                person_count = segment.metadata.get("person_count", 0)
                confidences = segment.metadata.get("confidences", [])

                if person_count > 0:
                    text = f"Persons: {person_count}"
                    cv2.putText(
                        frame,
                        text,
                        (10, 30),
                        cv2.FONT_HERSHEY_SIMPLEX,
                        1.0,
                        DebugVisualizer.COLORS["person"],
                        2,
                    )

                    for i, conf in enumerate(confidences):
                        conf_text = f"Person {i+1}: {conf:.2f}"
                        cv2.putText(
                            frame,
                            conf_text,
                            (10, 60 + i * 30),
                            cv2.FONT_HERSHEY_SIMPLEX,
                            0.6,
                            DebugVisualizer.COLORS["person"],
                            2,
                        )

                    annotated = True
                    break

        return annotated

    @staticmethod
    def _annotate_object_detections(
        frame, object_result: "ProcessorResult", frame_idx: int
    ) -> bool:
        """
        Annotate frame with object detection labels.

        Returns:
            True if annotations were added, False otherwise
        """
        if not object_result.segments:
            return False

        annotated = False
        for segment in object_result.segments:
            if segment.metadata.get("frame_index") == frame_idx:
                objects = segment.metadata.get("objects", [])

                if objects:
                    from collections import Counter

                    object_counts = Counter(objects)

                    y_offset = 30
                    for obj_name, count in object_counts.items():
                        text = f"{obj_name}: {count}"
                        cv2.putText(
                            frame,
                            text,
                            (frame.shape[1] - 200, y_offset),
                            cv2.FONT_HERSHEY_SIMPLEX,
                            0.6,
                            DebugVisualizer.COLORS["object"],
                            2,
                        )
                        y_offset += 30

                    annotated = True
                    break

        return annotated

    @staticmethod
    def _annotate_brand_detections(frame, brand_result: "ProcessorResult", frame_idx: int) -> bool:
        """
        Annotate frame with brand detection labels.

        Returns:
            True if annotations were added, False otherwise
        """
        data = brand_result.data
        if not data:
            return False

        brands_detected = data.get("brands_detected", [])

        if brands_detected:
            y_offset = frame.shape[0] - 60
            for i, brand in enumerate(brands_detected[:5]):
                text = f"Brand: {brand}"
                cv2.putText(
                    frame,
                    text,
                    (10, y_offset + i * 30),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.6,
                    DebugVisualizer.COLORS["brand"],
                    2,
                )

            return True

        return False
