#!/usr/bin/env python3
import json,re,sys,hashlib
from pathlib import Path
p=Path(sys.argv[1]);start=int(sys.argv[2]);end=int(sys.argv[3]);d=json.loads(p.read_text());errs=[]
CAST=['Nguyễn Lam Chi','Trần Vĩnh Phúc','Lê Thu Nguyệt','Phạm Hữu Tường','Đỗ Khánh An','Vũ Minh Triết'];POV='Nguyễn Lam Chi'
parts=d.get('parts',[])
if [x.get('part') for x in parts]!=list(range(start,end+1)):errs.append('part_range')
paras=[]
for x in parts:
 ps=x.get('paragraphs',[])
 if len(ps)!=12:errs.append(f"P{x.get('part')}_paragraph_count")
 paras.extend(ps)
 if x.get('pov',POV)!=POV:errs.append(f"P{x.get('part')}_pov")
if len(paras)!=48:errs.append('paragraph_total')
def text(x):return x if isinstance(x,str) else x.get('text') or x.get('narration') or ''
texts=[text(x).strip() for x in paras]
if any(not x for x in texts):errs.append('empty_paragraph')
words=sum(len(re.findall(r'\b\w+\b',x,re.UNICODE)) for x in texts)
if not 4650<=words<=5050:errs.append(f'word_count:{words}')
blob='\n'.join(texts)
for token in [r'\bE0[1-9]\b',r'\bA0[1-6]\b',r'cannot.support',r'placeholder',r'Aftercare',r'không teaser',r'P\d+D\d+']:
 if re.search(token,blob,re.I):errs.append('meta:'+token)
# Require every explicit three-token person name to be locked cast.
UP='A-ZĐÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÈÉẺẼẸÊỀẾỂỄỆÌÍỈĨỊÒÓỎÕỌÔỒỐỔỖỘƠỜỚỞỠỢÙÚỦŨỤƯỪỨỬỮỰỲÝỶỸỴ'
LO='a-zđàáảãạăằắẳẵặâầấẩẫậèéẻẽẹêềếểễệìíỉĩịòóỏõọôồốổỗộơờớởỡợùúủũụưừứửữựỳýỷỹỵ'
found=set(re.findall(rf'\b[{UP}][{LO}]+\s+[{UP}][{LO}]+\s+[{UP}][{LO}]+\b',blob))
extra=sorted(x for x in found if x not in CAST and not x.startswith(('Hội Đồng','Ngân Hàng','Cơ Quan','Mùa Nở')))
if extra:errs.append('extra_names:'+','.join(extra[:10]))
if len(set(texts))!=len(texts):errs.append('exact_paragraph_duplicate')
out={'status':'passed' if not errs else 'failed','sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'part_range':[start,end],'parts':len(parts),'paragraphs':len(paras),'words':words,'errors':errs};print(json.dumps(out,ensure_ascii=False));raise SystemExit(1 if errs else 0)
