"""Frame extraction from video files using ffmpeg."""

import os
import subprocess
import sys

from .utils import get_video_duration, is_hdr_video, tonemap_to_srgb_jpeg

NUM_FRAMES = 20
FRAME_WIDTH = 640
FRAME_HEIGHT = 360
HIGHRES_WIDTH = 1920
HIGHRES_HEIGHT = 1080


def extract_frames(
    video_path: str,
    output_dir: str,
    ffmpeg: str = "ffmpeg",
    ffprobe: str = "ffprobe",
) -> list[str]:
    """
    Extract NUM_FRAMES evenly distributed frames from a video file.

    Each frame is resized to FRAME_WIDTH x FRAME_HEIGHT using a blurred background
    filter so that non-16:9 content is displayed without black bars or stretching.

    For HDR (PQ / HLG) sources the frames are first extracted as 16-bit PNGs and
    then tone-mapped to sRGB JPEGs via macOS *sips*.

    Returns a list of absolute paths to the extracted frame images.
    """
    duration = get_video_duration(video_path, ffprobe=ffprobe)
    step = duration / NUM_FRAMES

    hdr = is_hdr_video(video_path, ffprobe=ffprobe)
    if hdr:
        print("   🎨 HDR-Video erkannt – verwende sips-Tonemapping für Frames.", file=sys.stderr)

    frame_paths: list[str] = []
    for i in range(NUM_FRAMES):
        timestamp = step * i + step / 2  # sample at the midpoint of each interval
        output_path = os.path.join(output_dir, f"frame_{i:02d}.jpg")

        # Blurred background filter: scales and crops to fill target size,
        # blurs to create background, then overlays the properly-scaled foreground.
        vf_filter = (
            f"[0:v]scale={FRAME_WIDTH}:{FRAME_HEIGHT}:force_original_aspect_ratio=increase,"
            f"crop={FRAME_WIDTH}:{FRAME_HEIGHT},boxblur=20[bg];"
            f"[0:v]scale={FRAME_WIDTH}:{FRAME_HEIGHT}:force_original_aspect_ratio=decrease[fg];"
            f"[bg][fg]overlay=(W-w)/2:(H-h)/2"
        )

        if hdr:
            # HDR path: extract as 16-bit PNG, then tonemap via sips
            png_path = output_path.replace(".jpg", ".png")
            subprocess.run(
                [
                    ffmpeg,
                    "-ss", str(timestamp),
                    "-i", video_path,
                    "-filter_complex", vf_filter,
                    "-vframes", "1",
                    "-pix_fmt", "rgb48le",
                    "-y",
                    png_path,
                ],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                check=True,
            )
            tonemap_to_srgb_jpeg(png_path, output_path)
            os.remove(png_path)
        else:
            subprocess.run(
                [
                    ffmpeg,
                    "-ss", str(timestamp),
                    "-i", video_path,
                    "-filter_complex", vf_filter,
                    "-vframes", "1",
                    "-q:v", "2",
                    "-y",
                    output_path,
                ],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                check=True,
            )
        frame_paths.append(output_path)

    return frame_paths


def extract_single_frame_highres(
    video_path: str,
    frame_index: int,
    output_path: str,
    ffmpeg: str = "ffmpeg",
    ffprobe: str = "ffprobe",
    *,
    duration: float | None = None,
    hdr: bool | None = None,
) -> str:
    """
    Extract a single frame at high resolution (1920x1080) from a video file.

    The frame_index determines which of the NUM_FRAMES intervals to sample from,
    using the same timestamp calculation as extract_frames().

    Args:
        video_path: Path to the input video file
        frame_index: Index of the frame to extract (0 to NUM_FRAMES-1)
        output_path: Path where the extracted frame should be saved
        ffmpeg: Path to the ffmpeg executable
        ffprobe: Path to the ffprobe executable
        duration: (keyword-only) Pre-computed video duration in seconds; avoids a
            duplicate ``ffprobe`` call when the caller already knows the duration.
        hdr: (keyword-only) Pre-computed HDR flag; avoids a duplicate ``ffprobe``
            call when the caller already knows the HDR status.

    Returns:
        The absolute path to the extracted frame image.
    """
    if not (0 <= frame_index < NUM_FRAMES):
        raise ValueError(f"frame_index must be between 0 and {NUM_FRAMES - 1}")

    if duration is None:
        duration = get_video_duration(video_path, ffprobe=ffprobe)
    if hdr is None:
        hdr = is_hdr_video(video_path, ffprobe=ffprobe)
    step = duration / NUM_FRAMES
    timestamp = step * frame_index + step / 2

    # Same blurred background filter as extract_frames, but in high resolution
    vf_filter = (
        f"[0:v]scale={HIGHRES_WIDTH}:{HIGHRES_HEIGHT}:force_original_aspect_ratio=increase,"
        f"crop={HIGHRES_WIDTH}:{HIGHRES_HEIGHT},boxblur=20[bg];"
        f"[0:v]scale={HIGHRES_WIDTH}:{HIGHRES_HEIGHT}:force_original_aspect_ratio=decrease[fg];"
        f"[bg][fg]overlay=(W-w)/2:(H-h)/2"
    )

    if hdr:
        # HDR path: extract as 16-bit PNG, then tonemap via sips
        png_path = output_path.replace(".jpg", ".png")
        subprocess.run(
            [
                ffmpeg,
                "-ss", str(timestamp),
                "-i", video_path,
                "-filter_complex", vf_filter,
                "-vframes", "1",
                "-pix_fmt", "rgb48le",
                "-y",
                png_path,
            ],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            check=True,
        )
        tonemap_to_srgb_jpeg(png_path, output_path)
        os.remove(png_path)
    else:
        subprocess.run(
            [
                ffmpeg,
                "-ss", str(timestamp),
                "-i", video_path,
                "-filter_complex", vf_filter,
                "-vframes", "1",
                "-q:v", "2",
                "-y",
                output_path,
            ],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            check=True,
        )

    return os.path.abspath(output_path)
