"""Compare gain and hard clipping on the generated Robot 36 practice WAV.

Usage: python reproduce-level-check.py ORIGINAL.wav OPEN_SSTV_REPO NEW_OUTPUT_DIR
Requires the pinned Open-SSTV dependencies, NumPy and Pillow. No audio device.
"""
from hashlib import sha256
from pathlib import Path
import json
import os
import subprocess
import sys
import tomllib
import wave

import numpy as np
from PIL import Image

source, repo, output = (Path(p).resolve() for p in sys.argv[1:])
base = "f773bd4fcb9da0c68ab915e9a1fa2c024bfdcc98"
expected = "dbb64c8cb34d3599c5aa7c36144746039632832da554eefff324a9fc68ae0166"
assert sha256(source.read_bytes()).hexdigest() == expected
subprocess.run(["git", "diff", "--exit-code", base, "--", "src"], cwd=repo, check=True)
output.mkdir(exist_ok=False)
with wave.open(str(source)) as wav:
    params = wav.getparams()
    assert (params.nchannels, params.sampwidth, params.framerate) == (1, 2, 48000)
    samples = np.frombuffer(wav.readframes(params.nframes), dtype="<i2").astype(float)

report = {
    "experiment": "Gain and hard clipping, 2026-11-09",
    "scope": "Generated PCM file, no added noise; not an SSTV app, microphone or RF test",
    "source_sha256": expected,
    "decoder_source_base": base,
    "decoder_checkout": subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=repo, text=True).strip(),
    "decoder_version": tomllib.loads((repo / "pyproject.toml").read_text())["project"]["version"],
    "python": sys.version.split()[0],
    "numpy": np.__version__,
    "sample_rate_hz": params.framerate,
    "duration_seconds": params.nframes / params.framerate,
    "new_upstream_submission": False,
    "cases": [],
}
control = None
for name, gain_db in [("original", 0), ("quiet-minus48db", -48), ("clipped-plus18db", 18)]:
    scaled = samples * 10 ** (gain_db / 20)
    clipped = (scaled > 32767) | (scaled < -32768)
    pcm = np.clip(np.rint(scaled), -32768, 32767).astype("<i2")
    wav_path, image_path = output / f"{name}.wav", output / f"{name}.png"
    with wave.open(str(wav_path), "wb") as wav:
        wav.setparams(params)
        wav.writeframes(pcm.tobytes())
    args = [sys.executable, "-m", "open_sstv.cli.decode", str(wav_path), "-o", str(image_path)]
    decoded = subprocess.run(args, cwd=repo, env={**os.environ, "PYTHONPATH": str(repo / "src")},
                             capture_output=True, text=True, timeout=180)
    log = (decoded.stdout + decoded.stderr).replace(str(output), "OUTPUT").replace(str(repo), "OPEN_SSTV_REPO")
    (output / f"{name}.log").write_text(log)
    dimensions, mae = None, None
    if image_path.exists():
        with Image.open(image_path) as image:
            pixels = np.asarray(image.convert("RGB"), dtype=np.int16)
        dimensions = [pixels.shape[1], pixels.shape[0]]
        if name == "original":
            control = pixels
        if control is not None and pixels.shape == control.shape:
            mae = float(np.abs(pixels - control).mean())
    row = {
        "name": name, "applied_gain_db": gain_db,
        "frames": len(pcm), "clipped_samples": int(clipped.sum()),
        "clipped_percent_all_samples": float(clipped.mean() * 100),
        "peak_int16": int(np.abs(pcm.astype(np.int32)).max()),
        "rms_int16": float(np.sqrt(np.mean(pcm.astype(float) ** 2))),
        "input_sha256": sha256(wav_path.read_bytes()).hexdigest(),
        "exit_code": decoded.returncode, "decoded_dimensions": dimensions,
        "image_mae_rgb_0_255_vs_original_decode": mae,
        "decoder_output": log,
        "decode_command": ["python", "-m", "open_sstv.cli.decode", wav_path.name, "-o", image_path.name],
    }
    report["cases"].append(row)
    (output / "report.json").write_text(json.dumps(report, indent=2) + "\n")
    print(json.dumps(row), flush=True)
assert report["cases"][0]["exit_code"] == 0 and report["cases"][0]["decoded_dimensions"] == [320, 240]
assert report["cases"][0]["clipped_samples"] == report["cases"][1]["clipped_samples"] == 0
assert report["cases"][2]["clipped_samples"] > 0
assert sha256(source.read_bytes()).hexdigest() == expected
