#!/usr/bin/env python3
from pathlib import Path
import datetime,hashlib,json,os
ROOT=Path('/data/video-pipeline/HaTramAudio/project/017-Tam-Ve-Khong-Ghi-Diem-Den');PID=ROOT.name;RUN='run-20260721T030911Z-51bf7fe4';OWNER='Levy';TITLE='Tấm Vé Không Ghi Điểm Đế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('artifact_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='Tại quầy hành lý thất lạc của một ga tàu cao tốc ở Hàng Châu, Tạ Minh Ý nhận được chiếc vali cũ chứa một tấm vé không ghi điểm đến. Manh mối ấy kéo cô trở lại câu hỏi gia đình đã bị bỏ ngỏ nhiều năm và buộc cô hợp tác với kỹ sư phục hồi tuyến đường sắt Giang Tự Hành. Giữa hồ sơ cũ, những chuyến tàu lỡ nhịp và các lựa chọn không thể làm thay người khác, họ dần học cách trao cho nhau sự thật, ranh giới và một cơ hội để cùng bước tiếp.'
 genres=['Ngôn tình đô thị','Bí ẩn đời thường','Chữa lành','Drama']
 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()
