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

PROJECT_ID="gacmai_20260716_233054"
RANGES=[(1,4),(5,8),(9,12)]

def sha(p): return hashlib.sha256(p.read_bytes()).hexdigest()
def fail(msg):
    print(json.dumps({"status":"failed","error":msg},ensure_ascii=False))
    raise SystemExit(1)

def main(outline_path,batch_paths,output_path):
    op=Path(outline_path); outline=json.loads(op.read_text()); outline_sha=sha(op)
    if outline.get("project_id")!=PROJECT_ID: fail("outline identity mismatch")
    all_parts=[]; sources=[]
    for expected,raw in zip(RANGES,batch_paths):
        p=Path(raw); d=json.loads(p.read_text()); file_sha=sha(p)
        if d.get("project_id")!=PROJECT_ID: fail(f"batch identity mismatch: {p}")
        if d.get("title")!=outline.get("title"): fail(f"batch title mismatch: {p}")
        if d.get("outline_sha256")!=outline_sha: fail(f"batch outline checksum mismatch: {p}")
        if d.get("part_range")!=list(expected): fail(f"batch range mismatch: {p}")
        parts=d.get("parts",[])
        if [x.get("part") for x in parts]!=list(range(expected[0],expected[1]+1)): fail(f"batch part order mismatch: {p}")
        for part in parts:
            paras=part.get("paragraphs")
            if not isinstance(paras,list) or len(paras)!=12: fail(f"part {part.get('part')} paragraph mismatch")
        all_parts.extend(parts); sources.append({"path":str(p),"sha256":file_sha,"part_range":list(expected)})
    if [x["part"] for x in all_parts]!=list(range(1,13)): fail("assembled parts not 1-12")
    story={"project_id":PROJECT_ID,"title":outline["title"],"outline_sha256":outline_sha,"named_characters":outline["cast"],"evidence_ids":[f"E{i:02d}" for i in range(1,10)],"pov":"limited_to_female_protagonist","closed_ending":True,"sources":sources,"parts":all_parts}
    out=Path(output_path);out.write_text(json.dumps(story,ensure_ascii=False,indent=2)+"\n")
    print(json.dumps({"status":"assembled_candidate","output":str(out),"sha256":sha(out),"parts":12,"paragraphs":144,"sources":sources},ensure_ascii=False))

if __name__=="__main__":
    if len(sys.argv)!=6: fail("usage: assembler OUTLINE BATCH1 BATCH2 BATCH3 OUTPUT")
    main(sys.argv[1],sys.argv[2:5],sys.argv[5])
