#!/usr/bin/env python3
"""Общая проверка контейнера, потоков, длительности, чёрных/замороженных кадров и громкости."""
from __future__ import annotations
import argparse, json, subprocess
from pathlib import Path

def run(cmd): return subprocess.run(cmd,capture_output=True,text=True)
def main():
    ap=argparse.ArgumentParser(); ap.add_argument('video'); ap.add_argument('--expected-duration',type=float); ap.add_argument('--timeline')
    ap.add_argument('--tolerance',type=float,default=0.10); ap.add_argument('--report',default='quality_report.json'); args=ap.parse_args()
    if args.timeline:
        args.expected_duration=float(json.loads(Path(args.timeline).read_text(encoding='utf-8'))['expected_duration'])
    v=Path(args.video)
    if not v.exists() or v.stat().st_size<100_000: raise SystemExit('Файл отсутствует или слишком мал')
    p=run(['ffprobe','-v','error','-show_streams','-show_format','-of','json',str(v)])
    if p.returncode: raise SystemExit(p.stderr)
    meta=json.loads(p.stdout); streams=meta.get('streams',[]); duration=float(meta['format'].get('duration',0) or 0)
    errors=[]; warnings=[]
    if not any(s.get('codec_type')=='video' for s in streams): errors.append('Нет видеопотока')
    if not any(s.get('codec_type')=='audio' for s in streams): errors.append('Нет аудиопотока')
    if args.expected_duration is not None and abs(duration-args.expected_duration)>args.tolerance:
        errors.append(f'Длительность {duration:.3f} не совпадает с ожидаемой {args.expected_duration:.3f}')
    black=run(['ffmpeg','-hide_banner','-i',str(v),'-vf','blackdetect=d=0.45:pix_th=0.10','-an','-f','null','-'])
    freeze=run(['ffmpeg','-hide_banner','-i',str(v),'-vf','freezedetect=n=-50dB:d=2','-an','-f','null','-'])
    loud=run(['ffmpeg','-hide_banner','-i',str(v),'-af','loudnorm=I=-14:TP=-1.5:LRA=8:print_format=json','-vn','-f','null','-'])
    report={'file':str(v),'bytes':v.stat().st_size,'duration':duration,'errors':errors,'warnings':warnings,
            'black_events':[x for x in black.stderr.splitlines() if 'black_start:' in x],
            'freeze_events':[x for x in freeze.stderr.splitlines() if 'freeze_' in x],
            'loudnorm_tail':loud.stderr[-2500:],'status':'ok' if not errors else 'failed'}
    Path(args.report).write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf-8')
    print(json.dumps(report,ensure_ascii=False,indent=2))
    if errors: raise SystemExit(2)
if __name__=='__main__': main()
