import argparse,copy,hashlib,json,re
from pathlib import Path

parser=argparse.ArgumentParser();parser.add_argument('--native-date',action='store_true');parser.add_argument('--suffix',default='');args=parser.parse_args()
private=Path(__file__).resolve().parent/'private-evidence';checks=[]
def check(ok,label):checks.append({'label':label,'passed':bool(ok)})
def equal(a,b):
    if type(a) is not type(b):return False
    if isinstance(a,dict):return a.keys()==b.keys() and all(equal(a[k],b[k]) for k in a)
    if isinstance(a,list):return len(a)==len(b) and all(equal(x,y) for x,y in zip(a,b))
    return a==b
def typed(raw):
    row=copy.deepcopy(raw)
    for key in ['id','use_number','prescription_number','employ','status','is_del','is_nutrition_station','is_own']:
        if key in row and row[key] is not None:row[key]=int(row[key])
    for key in ['use_weight','power','carbohydrate','protein','fat','sodium']:
        if key in row and row[key] is not None:
            value=float(row[key]);row[key]=int(value) if value.is_integer() else value
    if not args.native_date and isinstance(row.get('create_time'),str):row['create_time']=re.sub(r'\.0{1,6}$','',row['create_time'])
    return row
def media(value):return 'https://nutrition-media.invalid/'+value if value else ''
def expected(label,source):
    row=typed(source['nutrition'][0]);sets={r['uuid']:r for r in source['nutrition_set']};category={r['uuid']:r for r in source['nutrition_category']};set_row=sets[row['set_uuid']];cat=category[row['nutrition_category_uuid']]
    if label in ('pLists','mLists'):
        row['set_name']=set_row['name']
        for key in (['img_path','source_img_path','app_img'] if label=='pLists' else ['img_path','source_img_path']):row[key]=media(row[key])
        return {'code':0,'message':'请求成功','data':{'total':1,'rows':[row],'nutrition_sum':source['nutrition_sum']}}
    if label in ('pInfo','mInfo'):
        if row['employ']==0:row['employ']=''
        row['specifications']=row['specifications'] or ''
        for key in (['img_path','app_img'] if label=='pInfo' else ['img_path','source_img_path','app_img']):row[key]=media(row[key])
        if label=='pInfo':row['nutrition_category_name']=cat['name']
        return {'code':0,'message':'信息获取成功','data':row}
    if label in ('pTime','mTime'):
        return {'code':0,'message':'获取成功','data':[typed(r) for r in source['time_active_order']+source['time_inactive_order']]}
    if label in ('pSupplier','mSupplier'):return {'code':0,'message':'请求成功','data':source['supplier_expected']}
    if label=='mProduct':
        keys='id uuid name img_path specifications manufacturer supplier function synopsis app_img nutrition_category_uuid'.split()
        product={k:row[k] for k in keys};product.update(set_name=set_row['name'],category_name=cat['name'],demo=cat['demo']);product['img_path']=media(product['img_path']);product['app_img']=media(product['app_img'])
        return {'code':0,'message':'获取成功','data':{'rows':[{'category_name':cat['name'],'demo':cat['demo'],'list':[product]}],'total':1}}
    if label=='mGroup':
        keys='id uuid name sodium fat protein carbohydrate power use_weight use_number_unit use_weight_unit use_method employ use_number img_path specifications manufacturer supplier function synopsis app_img nutrition_category_uuid'.split()
        group={k:row[k] for k in keys};group.update(set_name=set_row['name'],category_name=cat['name'],demo=cat['demo']);group['img_path']=media(group['img_path'])
        units={str(i+1):name for i,name in enumerate(['袋','片','粒','个','根','勺','瓶','盒','份'])};group['use_weight_unit_cn']=units.get(row['use_weight_unit'],'');group['use_number_unit_cn']=units.get(row['use_number_unit'],'')
        time_names={r['uuid']:r['name'] for r in source['nutrition_time'] if int(r['del_flag'])==0};rows=[]
        assert row['employ']<=1,'Current bounded sample branch'
        for time in set_row['use_time'].split(','):
            record=copy.deepcopy(group);record['use_time']=time;record['use_time_name']=time_names[time];rows.append(record)
        return {'code':0,'message':'请求成功','data':rows}
    raise AssertionError(label)
for lane in ('B','C'):
    folder=private/(lane+'-http'+args.suffix);wire=[json.loads(line) for line in (folder/('private-retest-wire.jsonl' if args.suffix else 'private-wire.jsonl')).read_text().splitlines()];source=json.loads((folder/'private-http-baseline.json').read_text())
    check(len(wire)==(4 if args.suffix else 10),lane+':actual HTTP count');check(source==json.loads((folder/('private-retest-final-source.json' if args.suffix else 'private-final-source.json')).read_text()),lane+':final complete scope unchanged')
    for r in wire:
        label=lane+':'+r['label'];body=r['body'];parsed=json.loads(body)
        check(r['status']==200 and parsed['code']==0,label+':status/business')
        check(hashlib.sha256(body.encode()).hexdigest()==r['body_sha256'],label+':raw SHA')
        check(r['source_before']==source==r['source_after'],label+':product/dictionaries/actor/aggregate full source')
        check(equal(parsed,expected(r['label'],source)),label+':full DTO/types/shape/sort/native source')
        data=parsed['data'];check(bool(data.get('rows',data)) if isinstance(data,dict) else bool(data),label+':nonempty')
        check(source['p_lists_count']==source['m_lists_count']==source['product_join_count']==1,label+':fresh bounded unique where')
        sql=r['prepared_SQL'];check(bool(sql),label+':real DB prepared nonempty')
        check(all(re.match(r'^\s*(SELECT|SHOW|EXPLAIN)\b',q['queryString'],re.I) or q['queryString'].strip()=='CALL SP_TABLEDEF(?, ?)' for q in sql),label+':native readonly SQL')
        check(all(q.get('ok') is True and 'error' not in q for q in sql),label+':native SQL succeeded')
        check(all('ossaccesskey' not in json.dumps(q).casefold() for q in sql),label+':no OSS secret configuration query')
        image_keys={'pLists':['img_path','source_img_path','app_img'],'mLists':['img_path','source_img_path'],'pInfo':['img_path','app_img'],'mInfo':['img_path','source_img_path','app_img'],'mProduct':['img_path','app_img'],'mGroup':['img_path']}.get(r['label'],[])
        check(r['media_leaf_calls']==sum(bool(source['nutrition'][0][k]) for k in image_keys),label+':exact media leaf use count')
        if args.suffix and lane=='B':check(body==(private/'B-http'/('private-'+r['label']+'.httpbody')).read_text(),label+':original MySQL raw bytes unchanged')
        if args.suffix:
            module=r['label'][0];cls='app\\'+module+'\\logic\\Nutrition';sha='8a53cfd449a77b60461cd316e922a71aac6e28e1407ee25c4038abcffeab7837' if module=='p' else 'f98219d485b80624c6b0a9ee32b389845e03e1bec67d97e84b857e7a9e809b68';check(r['reflection'][cls]['sha256']==sha,label+':Reflection actual main SHA')
result={'passed':all(c['passed'] for c in checks),'assertions':len(checks),'mode':'native date' if args.native_date else 'MySQL seconds contract','failures':[c['label'] for c in checks if not c['passed']]};print(json.dumps(result,ensure_ascii=False,indent=2));raise SystemExit(0 if result['passed'] else 2)
