"""
PyAV audio padding processor.

Pads audio tracks with silence directly in-process (no HTTP).
Reuses the shared PyAV utilities from reflector.utils.audio_padding.
"""

import asyncio
import os
import tempfile

import av
import requests

from reflector.logger import logger
from reflector.processors.audio_padding import AudioPaddingProcessor, PaddingResponse
from reflector.processors.audio_padding_auto import AudioPaddingAutoProcessor
from reflector.utils.audio_padding import apply_audio_padding_to_file

S3_TIMEOUT = 60


class AudioPaddingPyavProcessor(AudioPaddingProcessor):
    """Audio padding processor using PyAV (no HTTP backend)."""

    async def pad_track(
        self,
        track_url: str,
        output_url: str,
        start_time_seconds: float,
        track_index: int,
    ) -> PaddingResponse:
        """Pad audio track with silence via PyAV.

        Args:
            track_url: Presigned GET URL for source audio track
            output_url: Presigned PUT URL for output WebM
            start_time_seconds: Amount of silence to prepend
            track_index: Track index for logging
        """
        if not track_url:
            raise ValueError("track_url cannot be empty")
        if start_time_seconds <= 0:
            raise ValueError(
                f"start_time_seconds must be positive, got {start_time_seconds}"
            )

        log = logger.bind(track_index=track_index, padding_seconds=start_time_seconds)
        log.info("Starting local PyAV padding")

        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(
            None,
            self._pad_track_blocking,
            track_url,
            output_url,
            start_time_seconds,
            track_index,
        )

    def _pad_track_blocking(
        self,
        track_url: str,
        output_url: str,
        start_time_seconds: float,
        track_index: int,
    ) -> PaddingResponse:
        """Blocking padding work: download, pad with PyAV, upload."""
        log = logger.bind(track_index=track_index, padding_seconds=start_time_seconds)
        temp_dir = tempfile.mkdtemp()
        input_path = None
        output_path = None

        try:
            # Download source audio
            log.info("Downloading track for local padding")
            response = requests.get(track_url, stream=True, timeout=S3_TIMEOUT)
            response.raise_for_status()

            input_path = os.path.join(temp_dir, "track.webm")
            total_bytes = 0
            with open(input_path, "wb") as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
                        total_bytes += len(chunk)
            log.info("Track downloaded", bytes=total_bytes)

            # Apply padding using shared PyAV utility
            output_path = os.path.join(temp_dir, "padded.webm")
            with av.open(input_path) as in_container:
                apply_audio_padding_to_file(
                    in_container,
                    output_path,
                    start_time_seconds,
                    track_index,
                    logger=logger,
                )

            file_size = os.path.getsize(output_path)
            log.info("Local padding complete", size=file_size)

            # Upload padded track
            log.info("Uploading padded track to S3")
            with open(output_path, "rb") as f:
                upload_response = requests.put(output_url, data=f, timeout=S3_TIMEOUT)
            upload_response.raise_for_status()
            log.info("Upload complete", size=file_size)

            return PaddingResponse(size=file_size)

        except Exception as e:
            log.error("Local padding failed", error=str(e), exc_info=True)
            raise
        finally:
            if input_path and os.path.exists(input_path):
                try:
                    os.unlink(input_path)
                except Exception as e:
                    log.warning("Failed to cleanup input file", error=str(e))
            if output_path and os.path.exists(output_path):
                try:
                    os.unlink(output_path)
                except Exception as e:
                    log.warning("Failed to cleanup output file", error=str(e))
            try:
                os.rmdir(temp_dir)
            except Exception as e:
                log.warning("Failed to cleanup temp directory", error=str(e))


AudioPaddingAutoProcessor.register("pyav", AudioPaddingPyavProcessor)
