"""Camera24 review method: every decoded frame, original timing, CPU only."""
import argparse
import csv
import hashlib
import json
import pathlib
import statistics
import subprocess
import time

parser = argparse.ArgumentParser()
parser.add_argument('--camera-id', type=int, required=True)
parser.add_argument('--root', type=pathlib.Path, default=pathlib.Path('/work'))
args = parser.parse_args()
root = args.root
original = root / f'inputs/camera{args.camera_id}_original.mp4'
review = root / f'inputs/camera{args.camera_id}_review.mp4'
mapping = root / f'inputs/camera{args.camera_id}_frame_map.csv'
assert not review.exists() and not mapping.exists(), 'Refuse overwrite'


def probe(path):
    command = ['ffprobe', '-v', 'error', '-threads', '2', '-select_streams', 'v:0',
        '-show_streams', '-show_frames', '-show_entries',
        'stream=codec_name,width,height,r_frame_rate,avg_frame_rate,time_base,duration,nb_frames:frame=best_effort_timestamp_time,key_frame,pict_type',
        '-of', 'json', str(path)]
    result = subprocess.run(command, capture_output=True, timeout=600, check=True)
    data = json.loads(result.stdout)
    data['decode_stderr'] = result.stderr.decode(errors='replace')[-3000:]
    return data


before = probe(original)
(root / 'reports/original_probe.json').write_text(json.dumps(before))
assert before.get('frames'), 'No decoded frames'
font = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
assert pathlib.Path(font).is_file(), 'Existing camera24 font is unavailable'
label = "Frame %{eif\\:n+1\\:d} | Time %{pts\\:hms}"
vf = "setpts=PTS-STARTPTS,drawtext=fontfile=" + font + ":text='" + label + "':fontsize=32:fontcolor=white:box=1:boxcolor=black@0.75:boxborderw=10:x=20:y=20"
started = time.monotonic()
result = subprocess.run(['ffmpeg', '-nostdin', '-hide_banner', '-loglevel', 'error', '-n',
    '-threads', '2', '-i', str(original), '-map', '0:v:0', '-an', '-vf', vf,
    '-c:v', 'libx264', '-preset', 'veryfast', '-crf', '20', '-threads', '2',
    '-fps_mode', 'passthrough', '-enc_time_base', '-1', '-movflags', '+faststart', str(review)],
    capture_output=True, timeout=900)
if result.returncode:
    print(result.stderr.decode(errors='replace')[-2000:])
    raise SystemExit(result.returncode)
after = probe(review)
(root / 'reports/review_probe.json').write_text(json.dumps(after))
a, b = before['frames'], after['frames']
assert len(a) == len(b), 'Frame count mismatch'
ta = [float(f['best_effort_timestamp_time']) for f in a]
tb = [float(f['best_effort_timestamp_time']) for f in b]
delta = max(abs((x - ta[0]) - (y - tb[0])) for x, y in zip(ta, tb))
assert delta < 0.001, 'Frame timestamps mismatch'
with mapping.open('x', newline='') as handle:
    writer = csv.writer(handle)
    writer.writerow(['frame_1based', 'original_pts_seconds', 'elapsed_seconds',
                     'review_pts_seconds', 'key_frame', 'pict_type'])
    for i, (x, y) in enumerate(zip(a, b), 1):
        writer.writerow([i, x['best_effort_timestamp_time'], f'{ta[i-1]-ta[0]:.6f}',
                         y['best_effort_timestamp_time'], x['key_frame'], x.get('pict_type')])
gaps = [y - x for x, y in zip(ta, ta[1:])]
median = statistics.median(gaps)
summary = dict(camera_id=args.camera_id, frame_count=len(a), first_pts=ta[0], last_pts=ta[-1],
    elapsed_seconds=ta[-1]-ta[0], max_mapping_error_seconds=delta,
    median_interval_seconds=median, max_interval_seconds=max(gaps),
    nonpositive_intervals=sum(x <= 0 for x in gaps),
    intervals_above_1p5x_median=sum(x > median * 1.5 for x in gaps),
    original_stream=before['streams'][0], review_stream=after['streams'][0],
    original_decode_errors=before['decode_stderr'], review_decode_errors=after['decode_stderr'],
    render_stderr=result.stderr.decode(errors='replace')[-1000:],
    render_wall_seconds=round(time.monotonic()-started, 3),
    source_frame_loss='Unverified without upstream reference; interval outliers are not proven frame loss.',
    visual_semantic_review='Not performed; repetition and scene annotations are user-owned.')
for path in (original, review, mapping):
    digest = hashlib.sha256()
    with path.open('rb') as handle:
        for chunk in iter(lambda: handle.read(1024*1024), b''):
            digest.update(chunk)
    summary[path.name] = {'bytes': path.stat().st_size, 'sha256': digest.hexdigest()}
(root / 'reports/video_validation.json').write_text(json.dumps(summary, indent=2))
print(json.dumps(summary))
raise SystemExit(1 if before['decode_stderr'] or after['decode_stderr'] or summary['nonpositive_intervals'] else 0)
