#!/usr/bin/env bash
# Manual: local HEVC encoder throughput preflight for upstream transport work; not part of CI.
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
STAMP="$(date +%Y%m%d-%H%M%S)"
OUTPUT_DIR="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_OUTPUT_DIR:-/tmp/lesavka-local-hevc-encoder-preflight-${STAMP}}"
SUMMARY_JSON="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_JSON:-${OUTPUT_DIR}/hevc-encoder-preflight.json}"
RUN_LOG="${OUTPUT_DIR}/hevc-encoder-preflight.log"
MODES="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_MODES:-1280x720@20,1280x720@30,1920x1080@20,1920x1080@30}"
DURATION_SECONDS="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_SECONDS:-5}"
BITRATE_KBIT="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_KBIT:-3000}"
MIN_REALTIME_FACTOR="${LESAVKA_LOCAL_HEVC_ENCODER_PREFLIGHT_MIN_REALTIME_FACTOR:-1.05}"
ENCODER="${LESAVKA_LOCAL_HEVC_ENCODER:-auto}"

mkdir -p "${OUTPUT_DIR}"

echo "==> local HEVC encoder preflight"
echo "   ↪ artifact_dir=${OUTPUT_DIR}"
echo "   ↪ summary_json=${SUMMARY_JSON}"
echo "   ↪ run_log=${RUN_LOG}"
echo "   ↪ modes=${MODES}"
echo "   ↪ duration=${DURATION_SECONDS}s bitrate=${BITRATE_KBIT}kbit min_realtime_factor=${MIN_REALTIME_FACTOR}"
echo "   ↪ no remote host, sudo, tunnel, or RCT capture is used"

(
  cd "${REPO_ROOT}"
  python3 - "$OUTPUT_DIR" "$SUMMARY_JSON" "$MODES" "$DURATION_SECONDS" "$BITRATE_KBIT" "$MIN_REALTIME_FACTOR" "$ENCODER" <<'PY'
import json
import os
import re
import subprocess
import sys
import time
from pathlib import Path

output_dir = Path(sys.argv[1])
summary_json = Path(sys.argv[2])
modes = [mode.strip() for mode in sys.argv[3].split(",") if mode.strip()]
duration_seconds = float(sys.argv[4])
bitrate_kbit = int(sys.argv[5])
min_realtime_factor = float(sys.argv[6])
encoder_override = sys.argv[7].strip()

ENCODER_ORDER = ["nvh265enc", "vah265enc", "vaapih265enc", "v4l2h265enc", "x265enc"]
MODE_RE = re.compile(r"^([0-9]+)x([0-9]+)@([0-9]+)$")


def gst_has(element: str) -> bool:
    return subprocess.run(
        ["gst-inspect-1.0", element],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
        check=False,
    ).returncode == 0


def pick_encoder() -> str:
    if encoder_override and encoder_override != "auto":
        if not gst_has(encoder_override):
            raise SystemExit(f"requested HEVC encoder is unavailable: {encoder_override}")
        return encoder_override
    for candidate in ENCODER_ORDER:
        if gst_has(candidate):
            return candidate
    raise SystemExit("no supported HEVC encoder found")


def encoder_chain(encoder: str, fps: int) -> str:
    if encoder == "x265enc":
        return (
            f"x265enc tune=zerolatency speed-preset=ultrafast "
            f"bitrate={bitrate_kbit} key-int-max={max(fps, 1)} log-level=none"
        )
    # Hardware encoder property names vary by driver. Use the bare element for
    # this availability/throughput preflight rather than failing on a missing
    # low-latency property that the runtime selector already probes separately.
    return encoder


def has_annex_b(path: Path) -> bool:
    data = path.read_bytes()
    return b"\x00\x00\x00\x01" in data or b"\x00\x00\x01" in data


def run_mode(encoder: str, mode: str) -> dict:
    match = MODE_RE.match(mode)
    if not match:
        raise SystemExit(f"invalid mode: {mode}")
    width, height, fps = map(int, match.groups())
    frame_count = max(1, int(round(duration_seconds * fps)))
    media_seconds = frame_count / fps
    out_path = output_dir / f"{mode.replace('@', '_')}-{encoder}.h265"
    pipeline = (
        f"videotestsrc num-buffers={frame_count} is-live=false pattern=smpte ! "
        f"video/x-raw,format=I420,width={width},height={height},framerate={fps}/1 ! "
        f"{encoder_chain(encoder, fps)} ! "
        "h265parse config-interval=-1 ! "
        "video/x-h265,stream-format=byte-stream,alignment=au ! "
        f"filesink location={out_path}"
    )
    timeout_seconds = max(10.0, media_seconds * 4.0)
    start = time.monotonic()
    proc = subprocess.run(
        ["timeout", f"{timeout_seconds:.1f}", "gst-launch-1.0", "-q", *pipeline.split()],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        check=False,
    )
    elapsed = max(time.monotonic() - start, 0.001)
    encoded_bytes = out_path.stat().st_size if out_path.exists() else 0
    realtime_factor = media_seconds / elapsed
    annex_b = encoded_bytes > 0 and has_annex_b(out_path)
    status = (
        "pass"
        if proc.returncode == 0 and encoded_bytes > 0 and annex_b and realtime_factor >= min_realtime_factor
        else "fail"
    )
    return {
        "mode": mode,
        "width": width,
        "height": height,
        "fps": fps,
        "frames": frame_count,
        "media_seconds": round(media_seconds, 3),
        "elapsed_seconds": round(elapsed, 3),
        "realtime_factor": round(realtime_factor, 3),
        "bytes": encoded_bytes,
        "annex_b": annex_b,
        "status": status,
        "artifact": str(out_path),
        "stderr_tail": "\n".join(proc.stderr.splitlines()[-12:]),
    }


encoder = pick_encoder()
results = [run_mode(encoder, mode) for mode in modes]
summary = {
    "schema": "lesavka.local-hevc-encoder-preflight.v1",
    "encoder": encoder,
    "duration_seconds": duration_seconds,
    "bitrate_kbit": bitrate_kbit,
    "min_realtime_factor": min_realtime_factor,
    "verdict": "pass" if all(row["status"] == "pass" for row in results) else "fail",
    "results": results,
}
summary_json.parent.mkdir(parents=True, exist_ok=True)
summary_json.write_text(json.dumps(summary, indent=2) + "\n")

print(f"encoder={encoder}")
for row in results:
    print(
        f"{row['status'].upper()} {row['mode']}: "
        f"frames={row['frames']} elapsed={row['elapsed_seconds']:.3f}s "
        f"rtx={row['realtime_factor']:.3f} bytes={row['bytes']} annex_b={row['annex_b']}"
    )

if summary["verdict"] != "pass":
    raise SystemExit("local HEVC encoder preflight failed")
PY
) 2>&1 | tee "${RUN_LOG}"

echo "==> done"
echo "artifact_dir: ${OUTPUT_DIR}"
echo "summary_json: ${SUMMARY_JSON}"
echo "run_log: ${RUN_LOG}"
