"""Keep ordinary mode0 colour/size separate from mode1 candidate eligibility."""
import hashlib,importlib.util,json
from pathlib import Path

spec=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
a=importlib.util.module_from_spec(spec);spec.loader.exec_module(a)
old=a.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=a.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=[hashlib.sha256(im.raw).hexdigest() for im in (old,new)]
owner=json.loads(Path('artifacts/galaxy-query-research/colonisation-colour/compatibility.json').read_text(encoding='utf-8'))
assert hashes==owner['sourceHashes']
functions=[];mode_calls=[]
for before in [0x3B26390,0x3B26BD0,0x3B27F00]:
    span=old.function(before);assert span and span[0]==before
    row=a.match(old,new,before,span[1]-before);assert row['status']=='unique',row
    row['oldRva']=hex(before);functions.append(row)
    ins=list(old.instructions(before,row['length']));modes=[]
    for index,call in enumerate(ins):
        if call.mnemonic=='call' and call.operands[0].type==a.cs.x86.X86_OP_IMM and call.operands[0].imm-old.base==0x3B1A200:
            producer=next(i for i in reversed(ins[:index]) if i.op_str.startswith('r9'))
            assert (producer.mnemonic,producer.op_str) in [('xor','r9d, r9d'),('mov','r9b, 1')],producer.op_str
            mode=int(producer.mnemonic=='mov');modes.append(mode)
            mode_calls.append(dict(function=hex(before),call=hex(call.address-old.base),mode=mode,producer=hex(producer.address-old.base)))
    assert modes==([1,0] if before==0x3B26BD0 else [0]),(hex(before),modes)
out=Path('artifacts/galaxy-query-research/colonisation-highlight/normal-mode-pair.json')
out.write_text(json.dumps(dict(sourceHashes=hashes,functions=functions,modeCalls=mode_calls,
    contract='Ordinary colour and independent size use mode0. The special colour tests radius plus mode1 before mode0 fallback. Per-star facts must keep both classifications; known mode0 null cannot use mode1 as a substitute.',
    runtimeValidated=False,gameProcessAccess=False),indent=2)+'\n',encoding='utf-8')
print(json.dumps(dict(functions=len(functions),modeCalls=mode_calls)))
