#!/usr/bin/env python3
import json,subprocess,sys
from datetime import datetime,timezone
from pathlib import Path
PROJECT=Path(__file__).resolve().parents[1];MANIFEST=PROJECT/'script/project-manifest.json';PLAN=PROJECT/'script/production-plan.json';REPORT=PROJECT/'log/production-verification.json'
def read(path):
 try:return json.loads(path.read_text())
 except:return None
def probe(path):return json.loads(subprocess.run(['ffprobe','-v','error','-show_entries','format=duration,size','-show_entries','stream=index,codec_name,width,height,sample_rate,channels','-of','json',str(path)],capture_output=True,text=True,check=True).stdout)
def main():
 issues=[];manifest=read(MANIFEST);plan=read(PLAN)
 if not manifest or not plan:raise RuntimeError('Manifest/plan missing')
 canon=manifest.get('canon_hash')
 if not canon or manifest.get('canon_version')!=1:issues.append('canon_not_promoted')
 if plan.get('canon_sha256')!=canon:issues.append('production_plan_canon_mismatch')
 if plan.get('reuse_previous_projects') is not False:issues.append('reuse_previous_not_forbidden')
 specs={'story':PROJECT/'story/promotion-report.json','tts':PROJECT/'log/tts-verification.json','images':PROJECT/'image/layout-manifest.json','intro':PROJECT/'log/intro-render.json','footage':PROJECT/'log/footage-job.json','final':PROJECT/'log/final-render.json','metadata':PROJECT/'log/metadata-verification.json'};receipts={}
 for name,path in specs.items():
  data=read(path);receipts[name]={'path':str(path.relative_to(PROJECT)),'present':data is not None}
  if not data:issues.append('missing_or_invalid_receipt:'+name);continue
  source=data.get('source_canon_sha256') or data.get('spoken_sha256');receipts[name].update({'verified':data.get('verified') is True,'source_canon_sha256':source})
  if data.get('verified') is not True:issues.append('receipt_not_verified:'+name)
  if name in ('images','footage','final') and data.get('visual_qa',{}).get('verified') is not True:issues.append('visual_qa_not_verified:'+name)
  if source!=canon:issues.append('receipt_canon_mismatch:'+name)
 final=PROJECT/'output/final.mp4';data=None
 if not final.exists():issues.append('final_missing')
 else:
  try:
   data=probe(final);streams=data.get('streams',[]);v=[x for x in streams if x.get('width')];a=[x for x in streams if x.get('sample_rate')]
   if len(v)!=1 or len(a)!=1:issues.append('final_stream_count')
   elif v[0].get('codec_name')!='h264' or (v[0].get('width'),v[0].get('height'))!=(1920,1080) or a[0].get('codec_name')!='aac':issues.append('final_codec_or_dimensions')
  except Exception as exc:issues.append('final_probe:'+str(exc))
 if not (PROJECT/'output/info.txt').exists():issues.append('metadata_file_missing')
 report={'version':1,'verified':not issues,'status':'passed' if not issues else 'failed','source_canon_sha256':canon,'receipts':receipts,'final':{'path':'output/final.mp4','probe':data},'issues':issues,'checked_at':datetime.now(timezone.utc).isoformat()};REPORT.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'verified':report['verified'],'issues':issues,'report':str(REPORT)},ensure_ascii=False));return 0 if report['verified'] else 1
if __name__=='__main__':sys.exit(main())
