import json,hashlib,datetime
from pathlib import Path
p=Path(__file__).parent
reports={l:json.loads((p/f'crud-green-{l}.json').read_text()) for l in 'BC'}
bodies={l:json.loads(Path(f'/private/tmp/cdx-ms-bodies-{l}.json').read_text()) for l in 'BC'}
refs={l:json.loads(Path(f'/private/tmp/cdx-ms-reference-{l}.json').read_text()) for l in 'BC'}
def normalize(body,lane,scenario):
    value=json.loads(json.dumps(body)); ref=refs[lane]; owned=reports[lane]['retained']
    if scenario=='select':
        matches=[x for x in value['data'] if x['id']==owned['strategy_id']]
        assert len(matches)==1 and matches[0]['strategy_name']==owned['marker']
        value['data']=matches  # Only this selected owned row, not all differing natural choices.
    def walk(v,path='$'):
        if isinstance(v,list):return [walk(x,path+f'[{i}]') for i,x in enumerate(v)]
        if not isinstance(v,dict):return v
        if 'strategy_name' in v:
            assert v['strategy_name']==owned['marker'] and type(v['id']) is int and v['id']==owned['strategy_id']
            v['strategy_name']='SOURCE_OWNED_MARKER';v['id']=1
            for key in ('create_time','update_time'):
                if key in v:
                    assert isinstance(v[key],str) and len(v[key])==19
                    datetime.datetime.strptime(v[key],'%Y-%m-%d %H:%M:%S')
                    v[key]='SOURCE_VERIFIED_SECOND_TIME'
            mappings={'department_uuids':ref['department']['uuid'],'department_names':ref['department']['name'],'identity_ids':int(ref['identity']['id']),'identity_names':ref['identity']['identity_type'],'restaurant_ids':int(ref['stall']['id']),'restaurant_names':ref['stall']['name']}
            for key,expected in mappings.items():
                if key in v:
                    if isinstance(v[key],list):assert v[key]==[expected];v[key]=[1 if isinstance(expected,int) else 'SOURCE_VERIFIED_REFERENCE']
                    else:assert v[key]==expected;v[key]='SOURCE_VERIFIED_REFERENCE'
        if '.time_ranges[' in path and 'start_time' in v:
            assert type(v['id']) is int and v['id']>0
            v['id']=1  # Per-phase relation ownership was independently validated before deletion.
        return {k:walk(x,path+'.'+k) for k,x in v.items()}
    return walk(value)
assert set(bodies['B'])==set(bodies['C']) and len(bodies['B'])==14
rows=[]
for key in bodies['B']:
    b,c=normalize(bodies['B'][key],'B',key),normalize(bodies['C'][key],'C',key)
    assert b==c,key
    rows.append({'scenario':key,'comparison_scope':'owned-selected-row-only' if key=='select' else 'complete-response-with-explicit-source-mapping','equal':True,'canonical_sha256':hashlib.sha256(json.dumps(b,ensure_ascii=False,sort_keys=True,separators=(',',':')).encode()).hexdigest()})
out={'passed':True,'scenarios':14,'full_response_scenarios':13,'selected_owned_row_scenarios':1,'mapping':'Owned main ID/marker, phase-owned range ID, verified natural references, verified valid second time; all types and other values/order unchanged','results':rows}
(p/'wire-comparison.json').write_text(json.dumps(out,ensure_ascii=False,indent=2)+'\n')
print('PASS: 13 complete source-mapped responses and 1 selected-owned-row projection; no natural select-list equality claim')
