#!/usr/bin/env python3
from pathlib import Path
import datetime,hashlib,json,os
ROOT=Path('/data/video-pipeline/HaTramAudio/project/020-Chiec-Nhan-Chi-Deo-Khi-Co-Nguoi-Nhin');PID=ROOT.name;RUN='run-20260721T124541Z-88551d8a';OWNER='Levy';TITLE='Chiếc Nhẫn Chỉ Đeo Khi Có Người Nhìn'
def now():return datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00','Z')
def sha(p):return hashlib.sha256(p.read_bytes()).hexdigest()
def guard():
 d=json.loads((ROOT/'.ownership-lock.json').read_text())
 for k,v in {'project_id':PID,'run_id':RUN,'owner':OWNER}.items():
  if d.get(k)!=v:raise RuntimeError('ownership mismatch '+k)
def atomic_text(p,s):
 guard();p.parent.mkdir(parents=True,exist_ok=True);t=p.with_name('.'+p.name+'.tmp');t.write_text(s);os.replace(t,p)
def atomic_json(p,d):atomic_text(p,json.dumps(d,ensure_ascii=False,indent=2)+'\n')
def main():
 guard();m=json.loads((ROOT/'script/project-manifest.json').read_text());canon=m.get('canon_sha256')
 story=m.get('gate_events',{}).get('story',{})
 if m.get('steps',{}).get('story')!='completed' or story.get('verified') is not True or story.get('canon_sha256')!=canon:raise RuntimeError('Story Gate is not committed/current')
 promo=json.loads((ROOT/'script/promotion-report.json').read_text());brief=ROOT/'script/story-brief.json'
 if not promo.get('verified') or promo.get('canon_sha256')!=canon or sha(ROOT/'story/story-canon.txt')!=canon:raise RuntimeError('canon promotion invalid')
 yt=f'Truyện Audio | {TITLE} (Full) | Hạ Trâm Audio'
 summary='Khi hai người được chọn cho một cuộc liên hôn đồng loạt từ chối, Tạ Minh Dao và Phó Cảnh Tuyên tự nguyện thay chỗ để hấp thụ áp lực danh dự của hai gia tộc trong một trăm hai mươi ngày. Họ thống nhất chỉ đeo nhẫn khi có người nhìn, cho đến khi nhận ra điều mình muốn giữ lại không phải danh vị của người thay thế mà là lựa chọn riêng tư giữa hai người.'
 genres=['Ngôn tình đô thị','Cưới trước yêu sau','Hào môn','Hài nhẹ']
 info=f'{yt}\n\n{summary}\n\nThể loại: '+', '.join(genres)+'\n\nTruyện được phát độc quyền tại Hạ Trâm Audio, nghiêm cấm sao chép dưới mọi hình thức\n'
 ip=ROOT/'output/info.txt';atomic_text(ip,info)
 metadata={'schema_version':1,'source_project_id':PID,'project_id':PID,'run_id':RUN,'status':'completed','verified':True,'source_canon_sha256':canon,'source_story_brief_sha256':sha(brief),'canonical_title':TITLE,'youtube_title':yt,'title_length':len(yt),'description':summary,'summary':summary,'genres':genres,'tags':[],'thumbnail_text':TITLE,'copyright_line':'Truyện được phát độc quyền tại Hạ Trâm Audio, nghiêm cấm sao chép dưới mọi hình thức','authority_sha256':{'story_canon':canon,'story_brief':sha(brief)},'contains_spoiler_reveal':False}
 mp=ROOT/'script/metadata.json';atomic_json(mp,metadata);receipt={**metadata,'artifact_path':str(ip),'artifact_sha256':sha(ip),'metadata_json_path':str(mp),'metadata_json_sha256':sha(mp),'completed_at':now()};atomic_json(ROOT/'log/metadata.json',receipt);print(json.dumps({'status':'completed','verified':True,'youtube_title':yt,'artifact_sha256':receipt['artifact_sha256']},ensure_ascii=False))
if __name__=='__main__':main()
