"""Identity-based NHL94 card associations and offline native 3bpp assets.

The original photo table uses roster indices, which cannot follow reordered
rosters. Resolve the name in the final ROM against a reviewed NHL-ID catalogue.
Reused photos remain in place; new NHL photos occupy unused ROM at2B0000.
"""
from pathlib import Path
import hashlib,json,struct,unicodedata

HERE=Path(__file__).resolve().parent
ASSETS=HERE/'player_cards'
TABLE=0x40e
TABLE_END=0x180e
PHOTO_BASE=0x2b0000
PHOTO_LIMIT=0x2f0000
PHOTO_BYTES=874

def identity(name):
    return ''.join(c for c in unicodedata.normalize('NFKD',name.lower().replace('_',' '))
                   if c.isascii() and c.isalnum())

def rosters(data):
    teams=[]
    for team in range(32):
        off=struct.unpack_from('>I',data,0x30e+4*team)[0]
        end=off+struct.unpack_from('>H',data,off+4)[0]-2
        pos=off+struct.unpack_from('>H',data,off)[0];row=[]
        while pos<end:
            n=struct.unpack_from('>H',data,pos)[0]
            assert n>=2 and n%2==0 and pos+n+8<=end
            row.append(data[pos+2:pos+n].rstrip(b'\0').decode('latin1'))
            pos+=n+8
        assert len(row)==26
        teams.append(row)
    return teams

def install(data,patch):
    manifest=json.loads((ASSETS/'manifest.json').read_text())
    assert hashlib.sha256(data[TABLE:TABLE_END]).hexdigest()==manifest['original_table_sha256'],'unexpected photo links'
    assert hashlib.sha256(data[0xc63f8+0x36a+32:0xc63f8+0x36a+64]).hexdigest()==manifest['palette_sha256'],'unexpected card palette'
    addresses={};pos=PHOTO_BASE
    for key,record in sorted(manifest['players'].items(),key=lambda item:item[1]['nhl_id']):
        if record['kind']=='original':
            ptr=record['pointer']
            assert hashlib.sha256(data[ptr:ptr+PHOTO_BYTES]).hexdigest()==record['sha256'],('original image changed',key)
        else:
            blob=(ASSETS/record['file']).read_bytes()
            assert len(blob)==PHOTO_BYTES and blob[:10]==bytes.fromhex('00000000000000000024')
            assert hashlib.sha256(blob).hexdigest()==record['sha256']
            assert pos+len(blob)<=PHOTO_LIMIT
            patch(pos,b'\xff'*len(blob),blob);ptr=pos;pos+=len(blob)
        addresses[key]=ptr
    report=[]
    for team,row in enumerate(rosters(data)):
        table=struct.unpack_from('>I',data,0x38e+team*4)[0]
        assert table==TABLE+160*team
        seen=set()
        for entry in range(26):
            off=table+entry*6;old,slot=struct.unpack_from('>IH',data,off)
            assert slot<26 and slot not in seen;seen.add(slot)
            name=row[slot];key=identity(name)
            assert key in addresses,f'No reviewed portrait identity for {team}:{slot}:{name}; rerun prepare_player_cards.py'
            ptr=addresses[key];record=manifest['players'][key]
            patch(off,struct.pack('>I',old),struct.pack('>I',ptr))
            report.append(dict(team=team,slot=slot,name=name,nhl_id=record['nhl_id'],kind=record['kind'],pointer=ptr,old_pointer=old))
        assert data[table+156:table+160]==b'\0'*4
    return dict(players=report,new_photo_bytes=pos-PHOTO_BASE,new_photo_end=pos,
                changed_links=sum(r['pointer']!=r['old_pointer'] for r in report),
                original_photos=sum(r['kind']=='original' for r in report),
                nhl_photos=sum(r['kind']=='nhl' for r in report),
                placeholders=sum(r['kind']=='nhl-placeholder' for r in report))
