import hashlib
import json
import subprocess
import sys
from pathlib import Path

import numpy as np

root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).parent
results = []
for angle in [45, 180, 360]:
    f = root / f"hyperframes-shutter-{angle}.mp4"
    p = json.loads(
        subprocess.check_output(
            ["ffprobe", "-v", "error", "-show_format", "-show_streams", "-of", "json", str(f)]
        )
    )
    v = next(s for s in p["streams"] if s["codec_type"] == "video")
    assert (
        int(v["nb_frames"]) == 72
        and v["avg_frame_rate"] == "24/1"
        and v["width"] == 1920
        and v["height"] == 1080
    )
    assert len([s for s in p["streams"] if s["codec_type"] == "audio"]) == 0
    timing = json.loads(
        subprocess.check_output(
            [
                "ffprobe",
                "-v",
                "error",
                "-select_streams",
                "v:0",
                "-show_entries",
                "frame=best_effort_timestamp_time",
                "-of",
                "json",
                str(f),
            ]
        )
    )
    times = [float(x["best_effort_timestamp_time"]) for x in timing["frames"]]
    assert len(times) == 72
    error = max(abs(t - i / 24) for i, t in enumerate(times))
    assert error < 0.000002
    raw = subprocess.check_output(
        [
            "ffmpeg",
            "-v",
            "error",
            "-i",
            str(f),
            "-vf",
            "crop=1920:4:0:580,format=rgb24",
            "-f",
            "rawvideo",
            "pipe:1",
        ]
    )
    rows = np.frombuffer(raw, dtype=np.uint8).reshape(72, 4, 1920, 3).astype(float).mean(axis=1)
    centers = []
    for row in rows:
        weights = np.maximum(row[:, 1] - np.median(row[:100, 1]), 0)
        weights[weights < 8] = 0
        centers.append(float((weights * np.arange(1920)).sum() / weights.sum()))
    differences = np.diff(centers[20:50])
    assert abs(np.median(differences) - 30) < 0.5
    row = rows[36]
    covered = np.where((row[:, 1] - row[:, 0] > 30) & (row[:, 1] > 80))[0]
    results.append(
        {
            "angle": angle,
            "durationSeconds": float(p["format"]["duration"]),
            "width": v["width"],
            "height": v["height"],
            "fps": v["avg_frame_rate"],
            "frames": int(v["nb_frames"]),
            "audioStreams": 0,
            "maximumTimestampErrorSeconds": error,
            "medianMarkerAdvancePixelsPerFrame": float(np.median(differences)),
            "midFrameAboveThresholdWidthPixels": int(covered[-1] - covered[0] + 1),
            "fileSha256": hashlib.sha256(f.read_bytes()).hexdigest(),
        }
    )
assert (
    results[0]["midFrameAboveThresholdWidthPixels"]
    < results[1]["midFrameAboveThresholdWidthPixels"]
    < results[2]["midFrameAboveThresholdWidthPixels"]
)
print(
    json.dumps(
        {
            "scope": "Decoded published native files only not physical exposure or model quality",
            "cases": results,
        },
        indent=2,
    )
)
