"""Lightweight scene detection wrapper using ffmpeg.

Detects scene changes, extracts frames at timestamps, and validates cut counts.
No PySceneDetect dependency — uses ffmpeg subprocess calls only.
"""

from __future__ import annotations

import re
import shutil
import subprocess
import tempfile
from pathlib import Path

# ── ffmpeg availability check (lazy — runs on first use, not import) ──────

def _require_ffmpeg() -> None:
    if not shutil.which("ffmpeg"):
        raise RuntimeError("ffmpeg not found — install via 'brew install ffmpeg'")


# ── Public API ─────────────────────────────────────────────────────────────


def detect_scene_changes(
    video_path: Path,
    threshold: float = 0.3,
) -> list[float]:
    """Detect scene change timestamps using ffmpeg scene detection.

    Returns list of timestamps (seconds) where cuts were detected.
    Uses ffmpeg's select filter with showinfo to extract pts_time values.
    """
    _require_ffmpeg()
    video_path = Path(video_path)
    if not video_path.exists():
        raise FileNotFoundError(f"Video not found: {video_path}")

    cmd = [
        "ffmpeg",
        "-i", str(video_path),
        "-vf", f"select='gt(scene,{threshold})',showinfo",
        "-f", "null",
        "-",
    ]

    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        timeout=300,
    )

    # showinfo output goes to stderr
    output = result.stderr

    # Parse pts_time from showinfo lines
    # Example line: [Parsed_showinfo_1 ...] n:   1 pts:  12345 pts_time:3.456 ...
    timestamps: list[float] = []
    for match in re.finditer(r"pts_time:\s*([\d.]+)", output):
        timestamps.append(float(match.group(1)))

    return sorted(timestamps)


def extract_frames_at(
    video_path: Path,
    timestamps: list[float],
    output_dir: Path | None = None,
) -> list[Path]:
    """Extract still frames at specific timestamps.

    Uses ffmpeg -ss {ts} -frames:v 1 for each timestamp.
    Output: {video_stem}_frame_{ts:.1f}s.png
    """
    _require_ffmpeg()
    video_path = Path(video_path)
    if not video_path.exists():
        raise FileNotFoundError(f"Video not found: {video_path}")

    if output_dir is None:
        output_dir = Path(tempfile.mkdtemp(prefix="scene_frames_"))
    else:
        output_dir = Path(output_dir)
        output_dir.mkdir(parents=True, exist_ok=True)

    extracted: list[Path] = []

    for ts in timestamps:
        out_file = output_dir / f"{video_path.stem}_frame_{ts:.1f}s.png"
        cmd = [
            "ffmpeg",
            "-y",
            "-ss", str(ts),
            "-i", str(video_path),
            "-frames:v", "1",
            "-q:v", "2",
            str(out_file),
        ]

        subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=60,
        )

        if out_file.exists():
            extracted.append(out_file)

    return extracted


def validate_cut_count(
    video_path: Path,
    expected_cuts: int,
    threshold: float = 0.3,
) -> dict:
    """Compare detected cuts to expected.

    Returns: {
        "expected": int, "detected": int, "match": bool,
        "timestamps": list[float],
        "status": "exact_match" | "over_cut" | "under_cut"
    }
    """
    timestamps = detect_scene_changes(video_path, threshold=threshold)
    detected = len(timestamps)

    if detected == expected_cuts:
        status = "exact_match"
    elif detected > expected_cuts:
        status = "over_cut"
    else:
        status = "under_cut"

    return {
        "expected": expected_cuts,
        "detected": detected,
        "match": detected == expected_cuts,
        "timestamps": timestamps,
        "status": status,
    }
