#!/usr/bin/env python3
import json,re,sys,hashlib
from pathlib import Path

FORBIDDEN = [
    r"bãi bồi|ngập lụt|đường nước|thủy lợi|nguồn nước|lối xuống nước",
    r"kiến trúc|trùng tu|phục dựng|quyền tác giả công trình",
    r"bệnh viện|y khoa|chẩn đoán|điều trị",
    r"dầu khí|xăng dầu|nhiên liệu",
    r"radio|băng ghi âm|băng cassette|ca khúc|bài hát|âm nhạc",
    r"ma quỷ|linh hồn|siêu nhiên",
    r"livestream",
]
FORBIDDEN_SKELETON = [
    r"xóa tên|bỏ tên|ghi tên|đứng tên|tác giả|cướp công|chiếm công|ghi nhận công lao",
    r"lịch sử phiên bản|dấu thời gian|người tạo bản đầu",
    r"thưởng hợp đồng|thưởng thương mại|đánh giá hiệu suất|gia hạn hợp đồng",
    r"sửa báo cáo thành tích|đính chính nguồn gốc|sửa hồ sơ tác giả",
]
REQUIRED = ["project_id","title","domain","injustice_mechanism","evidence_ledger","consent_privacy","authority_chain","public_payoff_venue","conditional_aftercare","cast","parts"]

def main():
    if len(sys.argv)!=2: raise SystemExit("usage: validate_concept.py FILE")
    p=Path(sys.argv[1]); raw=p.read_bytes(); d=json.loads(raw)
    errors=[]
    for k in REQUIRED:
        if k not in d: errors.append(f"missing:{k}")
    if d.get("project_id")!="gacmai_20260718_091744": errors.append("project_id")
    cast=d.get("cast",[])
    if len(cast)!=6: errors.append("cast_count")
    names=[x.get("name") for x in cast]
    if len(set(names))!=6 or any(not x for x in names): errors.append("cast_names")
    genders=[str(x.get("gender","")).lower() for x in cast]
    female=sum(x in ("female","nữ","woman") for x in genders); male=sum(x in ("male","nam","man") for x in genders)
    if (female,male)!=(3,3): errors.append("cast_gender_3_3")
    pov=[x for x in cast if x.get("pov") is True]
    if len(pov)!=1 or str(pov[0].get("gender","")).lower() not in ("female","nữ","woman"): errors.append("female_single_pov")
    parts=d.get("parts",[])
    if len(parts)!=12: errors.append("part_count")
    nums=[x.get("part") for x in parts]
    if nums!=list(range(1,13)): errors.append("part_numbers")
    # Scan story-bearing content only; exclusion/privacy declarations legitimately name forbidden domains in negated form.
    narrative_view={k:d.get(k) for k in ('title','domain','logline','injustice_mechanism','evidence_ledger','public_payoff_venue','parts')}
    txt=json.dumps(narrative_view,ensure_ascii=False).lower()
    txt=re.sub(r'"khong_livestream"\s*:\s*true\s*,?', '', txt)
    txt=re.sub(r'không\s+(?:có\s+)?livestream|không\s+phát\s+trực\s+tiếp', '', txt)
    hits=[]
    for pat in FORBIDDEN:
        m=re.search(pat,txt,re.I)
        if m:hits.append(m.group(0))
    if hits: errors.append("forbidden:"+",".join(sorted(set(hits))))
    skeleton_hits=[]
    for pat in FORBIDDEN_SKELETON:
        m=re.search(pat,txt,re.I)
        if m:skeleton_hits.append(m.group(0))
    if skeleton_hits: errors.append("forbidden_semantic_skeleton:"+",".join(sorted(set(skeleton_hits))))
    orig=d.get("originality_axes",{})
    for key in ("material_injustice","evidence_mechanics","tangible_payoff","emotional_core","authority_separation"):
        if not orig.get(key): errors.append("missing_originality_axis:"+key)
    for key in ("evidence_ledger","consent_privacy","authority_chain","public_payoff_venue","conditional_aftercare"):
        if not d.get(key): errors.append("empty:"+key)
    out={"status":"passed" if not errors else "failed","source":str(p),"source_sha256":hashlib.sha256(raw).hexdigest(),"errors":errors,"cast":len(cast),"women":female,"men":male,"parts":len(parts)}
    print(json.dumps(out,ensure_ascii=False,indent=2))
    if errors: raise SystemExit(1)
if __name__=="__main__": main()
