"""
Mock LTX Video worker implementation for testing without GPU resources.

This module provides the LTXVWorkerMock class that simulates video generation
using ffmpeg instead of the actual LTX Video model.
"""

import logging
import os
import subprocess
import tempfile
import time
from typing import Any, Dict

import requests

from auror.core.worker import Worker

logger = logging.getLogger(__name__)


class LTXVWorkerMock(Worker):
    """
    Mock worker for simulating LTX Video generation jobs.

    This worker creates simple test pattern videos using ffmpeg instead of
    running actual inference, useful for testing the pipeline without requiring
    GPU resources or the ltx_video dependency.
    """

    def __init__(self):
        """Initialize the mock LTXV worker."""
        super().__init__()
        logger.warning("Mock mode enabled - inference will be simulated")

    def process(self, job: Dict[str, Any]) -> None:
        """
        Process a video generation job using mock inference.

        Args:
            job: Job dictionary containing:
                - id: Unique job identifier
                - input: Input parameters including:
                    - prompt: Text prompt for video generation
                    - uploadUrl: Presigned URL for uploading the result
                    - seed: Random seed for reproducibility
                    - height: Output video height
                    - width: Output video width
                    - numFrames: Number of frames to generate

        Raises:
            Exception: If job processing fails at any stage
        """
        job_id = job["id"]
        output_dir = None

        try:
            logger.info(f"[{job_id}] Starting MOCK LTX Video job")

            # Create temporary output directory
            output_dir = tempfile.mkdtemp(prefix=f"ltxv_mock_{job_id}_")
            logger.info(f"[{job_id}] Output directory: {output_dir}")

            # Generate mock video
            logger.info(f"[{job_id}] Running MOCK inference...")
            output_mp4 = self._generate_mock_video(job, output_dir)

            # Upload result
            upload_url = job["input"]["uploadUrl"]
            logger.info(f"[{job_id}] Uploading result...")
            self._upload_output(output_mp4, upload_url)

            logger.info(f"[{job_id}] Job completed successfully")

        except Exception as e:
            logger.error(f"[{job_id}] Job failed: {e}", exc_info=True)
            raise

        finally:
            # Cleanup temporary files
            if output_dir and os.path.exists(output_dir):
                self._cleanup_directory(output_dir)
                logger.info(f"[{job_id}] Cleaned up temporary files")

    def _generate_mock_video(
        self, job: Dict[str, Any], output_dir: str, duration_seconds: float = 2.0
    ) -> str:
        """
        Generate a mock video using ffmpeg instead of running actual inference.

        This creates a simple test pattern video with the job parameters overlaid
        as text, useful for testing the pipeline without requiring GPU resources.

        Args:
            job: Job dictionary containing input parameters
            output_dir: Directory for output files
            duration_seconds: Duration of the mock video in seconds

        Returns:
            Path to the generated mock video file

        Raises:
            RuntimeError: If ffmpeg is not available or video generation fails
        """
        inp = job["input"]
        output_path = os.path.join(output_dir, "mock_output.mp4")

        # Calculate number of frames based on duration and FPS
        fps = 30
        total_frames = int(duration_seconds * fps)

        # Build text overlay with job parameters
        text_lines = [
            f"MOCK VIDEO",
            f"Prompt: {inp.get('prompt', 'N/A')[:50]}",
            f"Size: {inp.get('width', 'N/A')}x{inp.get('height', 'N/A')}",
            f"Frames: {inp.get('numFrames', 'N/A')}",
            f"Seed: {inp.get('seed', 'N/A')}",
        ]

        # Create a colorful test pattern with text overlay
        # Using testsrc2 which creates a moving test pattern
        ffmpeg_cmd = [
            "ffmpeg",
            "-f",
            "lavfi",
            "-i",
            f"testsrc2=size={inp.get('width', 1280)}x{inp.get('height', 720)}:rate={fps}:duration={duration_seconds}",
            "-vf",
            f"drawtext=text='{'|'.join(text_lines)}':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2",
            "-c:v",
            "libx264",
            "-pix_fmt",
            "yuv420p",
            "-y",
            output_path,
        ]

        logger.info(f"Generating mock video with ffmpeg: {' '.join(ffmpeg_cmd)}")

        try:
            # Run ffmpeg
            result = subprocess.run(
                ffmpeg_cmd,
                capture_output=True,
                text=True,
                check=True,
            )
            logger.info(f"Mock video generated successfully: {output_path}")

            # Simulate inference time (proportional to number of frames)
            mock_duration = min(3.0, inp.get("numFrames", 121) / 40)
            logger.info(f"Simulating inference time: {mock_duration:.1f}s")
            time.sleep(mock_duration)

            return output_path

        except FileNotFoundError:
            raise RuntimeError(
                "ffmpeg not found. Please install ffmpeg to use mock mode. "
                "Visit https://ffmpeg.org/download.html for installation instructions."
            )
        except subprocess.CalledProcessError as e:
            raise RuntimeError(
                f"Failed to generate mock video with ffmpeg: {e.stderr}"
            )

    def _upload_output(self, local_path: str, upload_url: str) -> None:
        """
        Upload the generated video to a presigned URL.

        Args:
            local_path: Path to the local video file
            upload_url: Presigned URL for upload

        Raises:
            requests.HTTPError: If the upload fails
        """
        logger.info(f"Uploading {local_path} to presigned URL")

        with open(local_path, "rb") as f:
            response = requests.put(upload_url, data=f)
            response.raise_for_status()

        logger.info("Upload complete")

    def _cleanup_directory(self, directory: str) -> None:
        """
        Clean up a directory and all its contents.

        Args:
            directory: Path to the directory to clean up

        Note:
            This method suppresses all exceptions to ensure cleanup
            doesn't fail the job.
        """
        try:
            for filename in os.listdir(directory):
                file_path = os.path.join(directory, filename)
                try:
                    if os.path.isfile(file_path):
                        os.remove(file_path)
                except Exception as e:
                    logger.warning(f"Failed to remove {file_path}: {e}")

            os.rmdir(directory)
        except Exception as e:
            logger.warning(f"Failed to remove directory {directory}: {e}")