#!/usr/bin/env python3
"""Bind mobile: real negative/positive requests and contemporaneous row receipts."""
import hashlib
import json
from pathlib import Path
import integrate_20261010 as tool
from integrate_20261011_batches46_48 import item

HERE=Path(__file__).resolve().parent
PRIVATE=Path('/Users/wiscourper/Documents/workspace/local/dm8-resume-connect-20261012.q6m3ar')
B=Path('/private/tmp/cdx-ai-hk-course-b.Kmdirn/runtime')
BASE='work_ai_api/2026-10-12-dm8-hk-course-batch/'
PINS={B/'bind-mobile-strong-CDXMBD0103FD5FF9C.json':'c4c5709f5ad0cbbaecdff3a5f2fd63a79ff295add2490510de34a8392be9e6da',
 PRIVATE/'bind-mobile-C.json':'ce99c01a55cd908ae5912fdbebbfb6286c85e1d65de304dae178348146bc4925',
 B/'bind-mobile-strong-raw-CDXMBD0103FD5FF9C.jsonl':'fdbf5cf3313f3c8c9c913a9c91d9c7d08b2c83dd4eaaac36306a904bb8c5dc85',
 B/'c-bind-mobile-strong-raw.jsonl':'7b5ce244c7066b23fbf96bdd72aa6ca9109bf3eae782232975fd7c8938466ea9'}

def verify():
    for p,h in PINS.items():assert hashlib.sha256(p.read_bytes()).hexdigest()==h
    responses=[]
    for receipt,rawpath,actor in [(B/'bind-mobile-strong-CDXMBD0103FD5FF9C.json',B/'bind-mobile-strong-raw-CDXMBD0103FD5FF9C.jsonl',46920),(PRIVATE/'bind-mobile-C.json',B/'c-bind-mobile-strong-raw.jsonl',1935)]:
        events=json.loads(receipt.read_text())['events']
        assert [r['phase'] for r in events]==['fixture_created','before_http','after_wrong_http','before_correct_http','after_correct_http','final_cache_readback']
        assert all(r['own_user_id']==actor for r in events)
        assert [r['at_epoch'] for r in events]==sorted(r['at_epoch'] for r in events)
        before,wrong,correct,final=events[1],events[2],events[4],events[5]
        assert before['mobile_type']==wrong['mobile_type']==correct['mobile_type']=='string'
        assert before['mobile_sha256']==wrong['mobile_sha256']==hashlib.sha256(b'').hexdigest()
        assert correct['mobile_sha256']==before['input_mobile_sha256'] and correct['mobile_sha256']!=before['mobile_sha256']
        assert wrong['pass'] and wrong['business_status']==500 and wrong['same_as_before']
        assert correct['pass'] and correct['business_status']==200 and correct['equals_input_mobile_hash'] and correct['captcha_consumed']
        assert correct['external_stub_delta_bytes']==0 and final['token_absent'] and final['captcha_absent']
        assert before['store_mapping_rows']==0
        rows=[json.loads(x) for x in rawpath.read_text().splitlines() if x];assert len(rows)==2
        bodies=[]
        for r,event,code in zip(rows,[wrong,correct],[500,200]):
            assert r['http']==200 and r['method']=='POST' and r['path']=='/api/User/bindMobile'
            assert hashlib.sha256(r['response_raw'].encode()).hexdigest()==event['response_raw_sha256']
            b=json.loads(r['response_raw']);assert b['status']==code;b.pop('trace_id',None);bodies.append(b)
        responses.append(json.dumps(bodies,sort_keys=True,ensure_ascii=False))
    assert responses[0]==responses[1]

if __name__=='__main__':
    audit=HERE/'integration-20261012-batch112.json';assert not audit.exists()
    targets=[item('ai_api','POST','/api/User/bindMobile',BASE,evidence=BASE+'BIND_MOBILE_STRONG_BC.md',
        readback='partial-evidence-before-and-after-own-mobile-type-and-input-hash-persisted-at-execution',
        success_case='partial-evidence-new-AI-user-without-Store-mapping-local-captcha-no-real-SMS',
        invalid_type='partial-evidence-wrong-captcha-rejected-and-mobile-unchanged',
        parity='partial-evidence-full-JSON-equal-except-trace-id-for-rejection-and-success',
        cleanup='new-marked-AI-users-retained-token-and-captcha-independent-absence-external-zero')]
    tool.main(targets,audit,verify)
