#!/usr/bin/env python3
from __future__ import annotations

import os
import sys
from pathlib import Path

from _media_utils import (
    DEFAULT_FRAME_FORMAT,
    die,
    ensure_parent_dir,
    format_seconds,
    is_youtube_url,
    parse_non_negative_float,
    parse_non_negative_int,
    require_command,
    resolve_ytdlp_urls,
    run_passthrough,
    timestamp_to_seconds,
)

USAGE = """\
Usage:
  download-frame.py [--dry-run] <video-file|youtube-url> <timestamp> <output-image>

Examples:
  download-frame.py clip.mp4 00:01:23 frame.jpg
  download-frame.py "https://www.youtube.com/watch?v=FXnC79xdnXQ" 15:42 frame.png

Environment:
  PREROLL_SECONDS  Seconds to seek before the target timestamp, then do a precise seek. Default: 2
  YTDLP_FORMAT     yt-dlp format selector for YouTube URLs. Default prefers video-only sources.
  YTDLP_JS_RUNTIMES Override yt-dlp JS runtimes. Default: auto-use node for YouTube when available.
  YTDLP_EXTRACTOR_ARGS Override yt-dlp extractor args. Default for YouTube: player_client=ios,android
  YTDLP_COOKIES_FROM_BROWSER Browser profile for yt-dlp cookies, if needed.
  YTDLP_COOKIES    Path to a cookies.txt file, if needed.
  YTDLP_EXTRA_ARGS Extra raw yt-dlp args split with shell rules.
  JPEG_QUALITY     ffmpeg q:v value for .jpg/.jpeg outputs. Lower is better. Default: 2
"""


def parse_args(argv: list[str]) -> tuple[bool, str, str, str]:
    dry_run = False
    if argv and argv[0] == "--dry-run":
        dry_run = True
        argv = argv[1:]

    if len(argv) != 3:
        print(USAGE.rstrip())
        raise SystemExit(1)

    return dry_run, argv[0], argv[1], argv[2]


def main(argv: list[str]) -> int:
    dry_run, input_arg, timestamp_arg, output_file = parse_args(argv)

    require_command("ffmpeg")

    try:
        target_seconds = timestamp_to_seconds(timestamp_arg)
        preroll = parse_non_negative_float(os.getenv("PREROLL_SECONDS", "2"), "PREROLL_SECONDS")
        jpeg_quality = parse_non_negative_int(os.getenv("JPEG_QUALITY", "2"), "JPEG_QUALITY")
    except ValueError as exc:
        die(str(exc))

    seek_from_seconds = max(target_seconds - preroll, 0.0)
    precise_seek_seconds = target_seconds - seek_from_seconds

    input_path = Path(input_arg)
    resolved_input = input_arg
    input_kind = "file"

    if input_path.is_file():
        resolved_input = str(input_path)
    elif is_youtube_url(input_arg):
        require_command("yt-dlp")
        format_selector = os.getenv("YTDLP_FORMAT", DEFAULT_FRAME_FORMAT)
        urls = resolve_ytdlp_urls(input_arg, format_selector)
        if not urls:
            die("yt-dlp did not return a video URL")
        resolved_input = urls[0]
        input_kind = "youtube"
    else:
        die("input must be an existing file or a YouTube URL")

    if dry_run:
        print(f"input_kind={input_kind}")
        print(f"input={input_arg}")
        print(f"resolved_input={resolved_input}")
        print(f"timestamp={timestamp_arg}")
        print(f"target_seconds={format_seconds(target_seconds)}")
        print(f"seek_from_seconds={format_seconds(seek_from_seconds)}")
        print(f"precise_seek_seconds={format_seconds(precise_seek_seconds)}")
        print(f"output_file={output_file}")
        return 0

    ensure_parent_dir(output_file)

    ffmpeg_args = [
        "ffmpeg",
        "-y",
        "-ss",
        format_seconds(seek_from_seconds),
        "-i",
        resolved_input,
        "-ss",
        format_seconds(precise_seek_seconds),
        "-map",
        "0:v:0",
        "-frames:v",
        "1",
        "-update",
        "1",
        "-an",
    ]

    if Path(output_file).suffix.lower() in {".jpg", ".jpeg"}:
        ffmpeg_args.extend(["-q:v", str(jpeg_quality)])

    ffmpeg_args.extend(["-f", "image2", output_file])
    run_passthrough(ffmpeg_args)
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
