# pylint: disable=broad-exception-caught

"""OpenCV-based frame extraction processor."""

import logging
import os
from typing import Optional

from mini_videorag.core.processor import ProcessorResult
from mini_videorag.processors.frame_extraction.base import (
    BaseFrameExtractionProcessor,
)
from mini_videorag.utils.clip_video import video_to_images, eliminate_duplicates


class OpenCVFrameExtractor(BaseFrameExtractionProcessor):
    """
    Extract frames from video using OpenCV/MoviePy.

    This processor extracts frames from a video and saves them to a directory.
    It also removes duplicate frames to optimize storage and processing.
    """

    def __init__(
        self,
        num_frames: int = 30,
        eliminate_duplicates_enabled: bool = True,
        diff_threshold: int = 25,
    ):
        """
        Initialize OpenCV frame extractor.

        Args:
            num_frames: Number of frames to extract (default: 30)
            eliminate_duplicates_enabled: Whether to remove duplicate frames (default: True)
            diff_threshold: Threshold for duplicate detection (default: 25)
        """
        self.num_frames = num_frames
        self.eliminate_duplicates_enabled = eliminate_duplicates_enabled
        self.diff_threshold = diff_threshold
        self.logger = logging.getLogger(__name__)

    @property
    def provider(self) -> str:
        """Provider name for this implementation."""
        return "opencv"

    def process(
        self, video_path: str, video_id: str, frames_dir: Optional[str] = None, **kwargs
    ) -> ProcessorResult:
        """
        Extract frames from video.

        Args:
            video_path: Path to video file
            video_id: Unique identifier
            frames_dir: Directory to save frames (required)
            **kwargs: Additional options
                - num_frames: Override default number of frames
                - eliminate_duplicates: Override default duplicate removal

        Returns:
            ProcessorResult with frame extraction data
        """
        try:
            self.validate_input(video_path)

            if not frames_dir:
                return ProcessorResult(
                    processor_name=self.name,
                    video_id=video_id,
                    success=False,
                    error="frames_dir is required for frame extraction",
                )

            num_frames = kwargs.get("num_frames", self.num_frames)
            eliminate_dups = kwargs.get("eliminate_duplicates", self.eliminate_duplicates_enabled)

            self.logger.info(f"Extracting {num_frames} frames from video: {video_id}")

            os.makedirs(frames_dir, exist_ok=True)

            video_to_images(video_path, frames_dir, num_frames)

            initial_frames = len(
                [f for f in os.listdir(frames_dir) if f.startswith("frame") and f.endswith(".png")]
            )

            frames_removed = 0
            if eliminate_dups:
                self.logger.info("Removing duplicate frames...")
                eliminate_duplicates(frames_dir, diff_threshold=self.diff_threshold)

                final_frames = len(
                    [
                        f
                        for f in os.listdir(frames_dir)
                        if f.startswith("frame") and f.endswith(".png")
                    ]
                )
                frames_removed = initial_frames - final_frames
            else:
                final_frames = initial_frames

            if final_frames == 0:
                return ProcessorResult(
                    processor_name=self.name,
                    video_id=video_id,
                    success=False,
                    error="No frames extracted from video",
                )

            self.logger.info(
                f"Frame extraction complete: {final_frames} frames "
                f"({frames_removed} duplicates removed)"
            )

            return ProcessorResult(
                processor_name=self.name,
                video_id=video_id,
                success=True,
                data={
                    "frames_dir": frames_dir,
                    "num_frames": final_frames,
                    "frames_extracted": initial_frames,
                    "duplicates_removed": frames_removed,
                    "eliminate_duplicates_enabled": eliminate_dups,
                },
                metadata={
                    "provider": self.provider,
                    "num_frames_requested": num_frames,
                    "diff_threshold": self.diff_threshold,
                },
            )

        except Exception as e:
            self.logger.error(f"Frame extraction failed: {e}", exc_info=True)
            return ProcessorResult(
                processor_name=self.name, video_id=video_id, success=False, error=str(e)
            )
