"""Check real adaptation coverage and asset frame contracts before a review build."""
from pathlib import Path
import json
import re
from PIL import Image

ROOT=Path(__file__).resolve().parents[1]
source=(ROOT/'content/prologue_source.txt').read_text()
book_quotes=re.findall(r"(?<!\w)'(?!\s)(.*?)(?<!\s)'(?!\w)",source)
story=json.loads((ROOT/'content/prologue.json').read_text())
dialogue=[e for e in story['events'] if e['kind']=='say']
compiled_quotes=[q for event in dialogue for q in event['quote_fragments']]
assert compiled_quotes==book_quotes,'Spoken text missing, altered or out of order'
characters=json.loads((ROOT/'content/characters.json').read_text())
for event in dialogue:
    assert event['speaker'] in characters,event
    assert event['expression'] in characters[event['speaker']]['portraits'],event
    paragraph=story['paragraphs'][event['source_paragraph']]
    assert all(q in paragraph for q in event['quote_fragments'])
    assert event['text']==' '.join(event['quote_fragments'])
for name,character in characters.items():
    atlas=ROOT/character['walk_atlas'].removeprefix('res://')
    image=Image.open(atlas).convert('RGBA')
    columns=character.get('walk_columns',3)
    assert image.size==(columns*48,256),(name,image.size)
    assert set(image.getchannel('A').getdata())<={0,255},name
    for row in range(4):
        for col in range(columns):
            frame=image.getchannel('A').crop((col*48,row*64,col*48+48,row*64+64))
            box=frame.getbbox()
            assert box is not None and box[0]>0 and box[1]>0 and box[2]<48 and box[3]<=61,(name,row,col,box)
    for expression,path in character['portraits'].items():
        portrait=Image.open(ROOT/path.removeprefix('res://')).convert('RGBA')
        assert portrait.size==(160,192),(name,expression,portrait.size)
        assert set(portrait.getchannel('A').getdata())<={0,255},(name,expression)
    for pose,path in character.get('poses',{}).items():
        strip=Image.open(ROOT/path.removeprefix('res://')).convert('RGBA')
        count=character.get('pose_frames',{}).get(pose,3)
        assert strip.size==(count*48,64),(name,pose,strip.size)
        assert set(strip.getchannel('A').getdata())<={0,255},(name,pose)
        for col in range(count):
            box=strip.getchannel('A').crop((col*48,0,col*48+48,64)).getbbox()
            assert box and box[0]>0 and box[1]>0 and box[2]<48 and box[3]<=61,(name,pose,col,box)
layout=json.loads((ROOT/'content/prologue_map.json').read_text())
assert len(layout['tiles'])==11 and all(len(row)==20 for row in layout['tiles'])
assert any(x==-1 for x in layout['tiles'][3]),'Parapet lacks crenellation gaps'
for name,pixels in layout['pixel_stops'].items():
    assert layout['stops'][name]==[pixels[0]//32,pixels[1]//32],name
assert Image.open(ROOT/'art/tiles/mocks_hold_floor_quiet_v2.png').size==(64,64)
assert Image.open(ROOT/'art/tiles/mocks_hold_tiles_v1.png').size==(128,128)
assert Image.open(ROOT/'art/environment/city_band_v4.png').size==(640,128)
print(f'PASS: {len(book_quotes)} exact spoken fragments in {len(dialogue)} paragraphs; 5 aligned animation atlases; 3 pose strips; 10 current busts; tile map and image contracts.')
