"""
Base class for video processors.

Video processors are responsible for extracting specific features from videos.
Each processor focuses on a single concern (transcription, OCR, music detection, etc.)
"""

import os
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field, field_validator, model_validator


@dataclass
class TimeSegment:
    """
    Represents a time segment in a video.

    Attributes:
        start: Start time in seconds
        end: End time in seconds
        metadata: Optional additional data about this segment
    """

    start: float
    end: float
    metadata: Optional[Dict[str, Any]] = None


class ProcessorResult(BaseModel):
    """
    Standard output format for all video processors.

    This ensures consistency across different processors and makes it easy
    to store, query, and display results.

    Uses Pydantic for validation:
    - Ensures error is set when success=False
    - Validates time segments don't have negative values
    - Type-safe with IDE autocomplete

    Attributes:
        processor_name: Identifier for the processor (e.g., "transcription", "music_detection")
        video_id: Unique identifier for the processed video
        success: Whether processing completed successfully
        data: Main result data (structure depends on processor type)
        segments: Time-based segments with associated data
        metadata: Additional processor-specific metadata
        error: Error message if processing failed (required when success=False)
    """

    processor_name: str
    video_id: str
    success: bool
    data: Dict[str, Any] = Field(default_factory=dict)
    segments: List[TimeSegment] = Field(default_factory=list)
    metadata: Dict[str, Any] = Field(default_factory=dict)
    error: Optional[str] = None

    class Config:
        arbitrary_types_allowed = True  # Allow TimeSegment dataclass

    @model_validator(mode="after")
    def validate_error_with_success(self) -> "ProcessorResult":
        """Validate error field based on success status."""
        if not self.success and not self.error:
            raise ValueError("error is required when success=False")
        if self.success and self.error:
            raise ValueError("error should be None when success=True")
        return self

    @field_validator("segments")
    @classmethod
    def validate_segments(cls, v: List[TimeSegment]) -> List[TimeSegment]:
        """Validate time segments have valid time ranges."""
        for segment in v:
            if segment.start < 0:
                raise ValueError(f"segment start time cannot be negative: {segment.start}")
            if segment.end < 0:
                raise ValueError(f"segment end time cannot be negative: {segment.end}")
            if segment.start > segment.end:
                raise ValueError(
                    f"segment start ({segment.start}) cannot be after end ({segment.end})"
                )
        return v


# pylint: disable=unnecessary-ellipsis
class BaseVideoProcessor(ABC):
    """
    Abstract base class for all video processors.

    Processors are stateless operations that take a video file path and
    produce structured results. They should be:
    - Independent: No dependencies on other processors
    - Idempotent: Same input produces same output
    - Focused: Each processor does one thing well

    Example:
        class MusicDetectionProcessor(BaseVideoProcessor):
            @property
            def name(self) -> str:
                return "music_detection"

            def process(self, video_path: str, video_id: str, **kwargs) -> ProcessorResult:
                # Detect music in video
                has_music = detect_music(video_path)
                return ProcessorResult(
                    processor_name=self.name,
                    video_id=video_id,
                    success=True,
                    data={"has_music": has_music},
                    segments=[TimeSegment(start=0, end=10, metadata={"confidence": 0.9})]
                )
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """
        Unique identifier for this processor.

        Should be lowercase with underscores (e.g., "music_detection", "ocr_subtitles").
        This name is used in configuration and result storage.
        """
        ...

    @abstractmethod
    def process(self, video_path: str, video_id: str, **kwargs) -> ProcessorResult:
        """
        Process a video and extract features.

        Args:
            video_path: Local file path to the video file
            video_id: Unique identifier for this video
            **kwargs: Additional processor-specific parameters

        Returns:
            ProcessorResult containing the extracted features

        Raises:
            Exception: If processing fails (should set success=False and error message)
        """
        ...

    def validate_input(self, video_path: str) -> bool:
        """
        Validate that the video file exists and is accessible.

        Override this method to add processor-specific validation.

        Args:
            video_path: Path to video file

        Returns:
            True if input is valid

        Raises:
            FileNotFoundError: If video file doesn't exist
            ValueError: If file format is not supported
        """
        if not os.path.exists(video_path):
            raise FileNotFoundError(f"Video file not found: {video_path}")
        return True

    @property
    def supported_formats(self) -> List[str]:
        """
        List of supported video formats (file extensions).

        Override to specify processor-specific format requirements.
        Default supports common video formats.

        Returns:
            List of supported file extensions (e.g., ['.mp4', '.avi', '.mov'])
        """
        return [".mp4", ".avi", ".mov", ".mkv", ".webm", ".flv"]

    @property
    def requires_audio(self) -> bool:
        """
        Whether this processor requires audio track in the video.

        Override to return True for audio-based processors (transcription, music detection).
        """
        return False

    @property
    def requires_video(self) -> bool:
        """
        Whether this processor requires video frames.

        Override to return True for visual processors (OCR, object detection).
        """
        return True
