# pylint: disable=broad-exception-caught

"""OpenAI Whisper transcription processor."""

import logging
import os
import tempfile
from typing import Optional

from openai import OpenAI

from mini_videorag.core.processor import ProcessorResult
from mini_videorag.core.exceptions import (
    VideoLoadError,
    InsufficientDataError,
    ProcessingError,
)
from mini_videorag.processors.transcription.base import BaseTranscriptionProcessor
from mini_videorag.utils.download_video import download_video_from_url
from mini_videorag.utils.audio_utils import video_to_audio


class OpenAIWhisperProcessor(BaseTranscriptionProcessor):
    """
    Transcribes video audio using OpenAI Whisper API.

    Extracts audio from video and generates both original language
    and English transcripts.
    """

    def __init__(
        self,
        openai_client: Optional[OpenAI] = None,
        translation_model: str = "gpt-3.5-turbo",
    ):
        """
        Initialize OpenAI Whisper processor.

        Args:
            openai_client: OpenAI client instance. If None, creates from OPENAI_API_KEY env var.
            translation_model: OpenAI model to use for translation. Defaults to gpt-3.5-turbo.
        """
        if openai_client is None:
            api_key = os.getenv("OPENAI_API_KEY")
            if not api_key:
                raise ValueError(
                    "openai_client not provided and OPENAI_API_KEY not set. "
                    "Either pass openai_client or set OPENAI_API_KEY environment variable."
                )
            openai_client = OpenAI(api_key=api_key)

        self.openai_client = openai_client
        self.translation_model = translation_model
        self.logger = logging.getLogger(__name__)

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

    def _audio_to_text(self, audio_path: str) -> str:
        """Convert audio file to text using OpenAI Whisper."""
        with open(audio_path, "rb") as audio_file:
            transcription = self.openai_client.audio.transcriptions.create(
                model="gpt-4o-transcribe", file=audio_file
            )
            return transcription.text

    def _translate(self, text: str, language: str = "english") -> str:
        """Translate text to target language using OpenAI."""
        response = self.openai_client.chat.completions.create(
            model=self.translation_model,
            messages=[
                {
                    "role": "system",
                    "content": f"You are a translator. Translate the following text to {language}."
                    f" Only provide the translation, no explanations."
                    f" If text is already in {language}, return it unchanged.",
                },
                {"role": "user", "content": text},
            ],
        )
        return response.choices[0].message.content.strip()

    def process(self, video_path: str, video_id: str, **kwargs) -> ProcessorResult:
        """
        Transcribe video audio.

        Args:
            video_path: Path to video file
            video_id: Unique identifier
            **kwargs: Optional 'video_url' to download from URL

        Returns:
            ProcessorResult with transcription data
        """
        try:
            self.logger.info(f"Starting transcription for video: {video_id}")

            with tempfile.TemporaryDirectory() as temp_dir:
                if "video_url" in kwargs and not os.path.exists(video_path):
                    video_url = kwargs["video_url"]
                    self.logger.debug(f"Downloading video from: {video_url}")
                    try:
                        download_video_from_url(video_url, video_path)
                    except Exception as e:
                        raise VideoLoadError(f"Failed to download video from URL: {e}") from e

                self.validate_input(video_path)

                audio_path = os.path.join(temp_dir, "audio.mp3")
                self.logger.debug("Extracting audio from video")
                try:
                    video_to_audio(video_path, audio_path)
                except Exception as e:
                    raise InsufficientDataError(
                        f"Failed to extract audio (video may have no audio track): {e}"
                    ) from e

                self.logger.debug("Transcribing audio")
                try:
                    original_transcript = self._audio_to_text(audio_path)
                except Exception as e:
                    raise ProcessingError(f"Failed to transcribe audio: {e}") from e

                self.logger.debug("Translating to English")
                try:
                    english_transcript = self._translate(original_transcript)
                except Exception as e:
                    raise ProcessingError(f"Failed to translate transcript: {e}") from e

                return ProcessorResult(
                    processor_name=self.name,
                    video_id=video_id,
                    success=True,
                    data={
                        "original_transcript": original_transcript,
                        "english_transcript": english_transcript,
                    },
                    metadata={
                        "audio_extracted": True,
                        "translation_performed": True,
                    },
                )

        except VideoLoadError as e:
            self.logger.error(f"Transcription failed - video load error: {e}", exc_info=True)
            return ProcessorResult(
                processor_name=self.name,
                video_id=video_id,
                success=False,
                error=f"VideoLoadError: {e}",
            )
        except InsufficientDataError as e:
            self.logger.error(f"Transcription failed - insufficient data: {e}", exc_info=True)
            return ProcessorResult(
                processor_name=self.name,
                video_id=video_id,
                success=False,
                error=f"InsufficientDataError: {e}",
            )
        except ProcessingError as e:
            self.logger.error(f"Transcription failed - processing error: {e}", exc_info=True)
            return ProcessorResult(
                processor_name=self.name,
                video_id=video_id,
                success=False,
                error=f"ProcessingError: {e}",
            )
        except Exception as e:
            self.logger.error(f"Transcription failed - unexpected error: {e}", exc_info=True)
            return ProcessorResult(
                processor_name=self.name,
                video_id=video_id,
                success=False,
                error=f"UnexpectedError: {e}",
            )
