import copy, hashlib, json, shutil
from pathlib import Path
from urllib.parse import urlencode
P=Path(__file__).resolve().parent
main=P.parents[3]/'zhctproject/ai_api'
assert hashlib.sha256((main/'app/api/service/RopeSkipping.php').read_bytes()).hexdigest()=='616e3d0b3c6851a37c5e76981eec82a63dd499b5358bbf5ff0cb83a11c808762'
source=P/'source'
if not source.exists():
    source.mkdir()
    for name in ['app','cores','config','extend','route','vendor']:
        shutil.copytree(main/name,source/name,ignore=shutil.ignore_patterns('._*','__MACOSX'))
    for name in ['composer.json','version.json']:
        if (main/name).exists(): shutil.copy2(main/name,source/name)
files={str(f.relative_to(source)):hashlib.sha256(f.read_bytes()).hexdigest() for f in sorted(source.rglob('*')) if f.is_file()}
assert all(hashlib.sha256((main/name).read_bytes()).hexdigest()==sha for name,sha in files.items())
(P/'source-frozen-sha.json').write_text(json.dumps({'files':files},indent=2)+'\n')
for lane in ['B','C']:
    records=[]
    for i in range(2):
        values={'store_id':str(2147001111+i),'store_name':f'CDXRE11D7C2_STORE{i+1}','describe':'CDXRE11D7C2 Rope HTTP fixture','logo_image_id':'0','sort':'0','is_recycle':'0','host':f'rope{i+1}.exact.invalid','version_type':'0','is_delete':'0','create_time':'0','update_time':'0'}
        if lane=='B': values.update({'group_id':'0','group_name':'','types':'','status':'1','contact_name':'','contact_phone':'','address':''})
        quote=(lambda s:'`'+s+'`') if lane=='B' else (lambda s:'"'+s.upper()+'"')
        sql='INSERT INTO '+quote('yoshop_store')+' ('+','.join(map(quote,values))+') VALUES ('+','.join('?' for _ in values)+')'
        records.append({'sql':sql,'bindValue':[{'position':n+1,'value':v,'pdo_type':2} for n,v in enumerate(values.values())],'expected':values,'expected_affected':1})
    (P/f'store-plan-{lane}.json').write_text(json.dumps({'lane':lane,'INSERT':2,'commit':1,'rows':records,'readback':'SELECT * FROM yoshop_store WHERE store_id IN (?,?) ORDER BY store_id','readback_params':['2147001111','2147001112'],'retain':True,'generator_advances_from':2147000703,'generator_minimum_after':2147001113},indent=2)+'\n')
forms=[]
for label,value,date,count,duration in [('A','1790000000123','2097-11-02','101','61'),('B','9007199254740991','2097-11-01','102','62'),('C','9007199254740993','2097-11-02','103','63'),('D','9223372036854775807','2097-11-01','104','64')]:
    form={'mac':'CDXRE11D7C2_'+label,'mode':'free','modeLabel':'CDX精确跳绳','stoppedAt':value,'dateKey':date,'dateLabel':'2097 marker','timeLabel':'12:34:56','count':count,'duration':duration,'calories':'12.25','fatBurnEfficiency':'0.1250','avgFreq':'100','maxFreq':'120','mostJump':'90','ropeTrips':'2','target':{'seconds':'60'},'data':[{'second':'1','count':'3'},{'second':'2','count':'4'}]}
    forms.append(form)
def flatten(value,prefix):
    if isinstance(value,dict): return [pair for k,v in value.items() for pair in flatten(v,prefix+'['+k+']')]
    if isinstance(value,list): return [pair for i,v in enumerate(value) for pair in flatten(v,prefix+'['+str(i)+']')]
    return [(prefix,value)]
cases={}
def add(name,method,path,form=None,query='',actor='one',host='rope1.exact.invalid',expected='success'):
    cases[name]={'method':method,'path':path,'query':query,'body_raw':urlencode(flatten(form,'form')) if form is not None else '', 'actor':actor,'host':host,'platform':'APP','version':'2.0.46','expected':expected}
for i,form in enumerate(forms):
    label=chr(65+i);add('ADD_'+label,'POST','/api/RopeSkipping/add',form)
    cases['ADD_'+label]['form']=form
    add('LATEST_'+label,'GET','/api/RopeSkipping/latest')
for label,query in [('ALL',''),('P1','pagesize=1&page=1'),('P2','pagesize=1&page=2'),('P3','pagesize=1&page=3')]: add('LIST_'+label,'GET','/api/RopeSkipping/list',query=query)
add('EMPTY_LATEST','GET','/api/RopeSkipping/latest',actor='two',host='rope2.exact.invalid')
add('EMPTY_LIST','GET','/api/RopeSkipping/list',actor='two',host='rope2.exact.invalid')
add('CROSS_TOKEN','GET','/api/RopeSkipping/latest',actor='two',expected='user_missing')
add('MISSING_TOKEN','GET','/api/RopeSkipping/latest',actor='none',expected='token_missing')
for label,value in [('OVER','9223372036854775808'),('ABC','abc'),('ARRAY',{'x':'1'}),('MISSING',None)]:
    form=copy.deepcopy(forms[0]);form['mac']='CDXRE11D7C2_INVALID_'+label
    if value is None: del form['stoppedAt']
    else: form['stoppedAt']=value
    add('INVALID_'+label,'POST','/api/RopeSkipping/add',form,expected='required' if label=='MISSING' else 'integer')
assert len(cases)==20
(P/'cases.json').write_text(json.dumps(cases,ensure_ascii=False,indent=2)+'\n')
pin_files=list(P.glob('*.php'))+[P/'cases.json',P/'store-plan-B.json',P/'store-plan-C.json',P/'source-frozen-sha.json']
(P/'execution-pins.json').write_text(json.dumps({f.name:hashlib.sha256(f.read_bytes()).hexdigest() for f in sorted(pin_files)},indent=2)+'\n')
print(json.dumps({'source_files':len(files),'cases_per_lane':len(cases),'store_INSERT_per_lane':2,'formal_rope_INSERT_per_lane':4,'HTTP':0,'DML':0,'DDL':0}))
