"""合成离线样本检查。与同名 JSON 及文中列出的附件放在同一目录运行。"""
from pathlib import Path, PurePosixPath
import base64, hashlib, io, inspect, json, math, re, subprocess, sys, tempfile, wave, zipfile
from collections import Counter, defaultdict
from datetime import date, datetime
from decimal import Decimal
sys.dont_write_bytecode=True

def sha(b): return hashlib.sha256(b).hexdigest()
def rejected(fn):
    try: fn()
    except (ValueError,TypeError,KeyError,UnicodeError,OverflowError): return True
    return False

def git(root,*args,input=None,check=True):
    r=subprocess.run(['git','-c','core.autocrlf=false',*args],cwd=root,input=input,capture_output=True,check=check)
    return r

def verify(d,base):
    def audit(rows):
        calls={};results=defaultdict(list);issues=[]
        for i,r in enumerate(rows):
            if r['type'] not in ('function_call','function_call_output'):continue
            if 'call_id' not in r:
                issues.append({'kind':'invalid_call_id','index':i,'reason':'missing'});continue
            key=r['call_id']
            if not isinstance(key,str):
                issues.append({'kind':'invalid_call_id','index':i,'reason':'not_string'});continue
            if not key:
                issues.append({'kind':'invalid_call_id','index':i,'reason':'empty'});continue
            if r['type']=='function_call':
                if key in calls:issues.append({'kind':'duplicate_call','call_id':key,'index':i})
                else:calls[key]=i
            elif r['type']=='function_call_output':
                if key not in calls:issues.append({'kind':'orphan_output','call_id':key,'index':i})
                results[key].append(i)
                if len(results[key])>1:issues.append({'kind':'duplicate_output','call_id':key,'index':i})
        for key,index in calls.items():
            if key not in results:issues.append({'kind':'missing_output','call_id':key,'index':index})
        return issues
    assert not audit(d['normal']);issues=audit(d['bad'])
    assert sorted({x['kind'] for x in issues})==d['expected_issues']
    invalid=audit(d['invalid_ids']);assert len(invalid)==len(d['invalid_ids'])
    assert all(r['kind']=='invalid_call_id' and r['index']==i for i,r in enumerate(invalid))
    empty_pair=audit([{'type':'function_call','call_id':''},{'type':'function_call_output','call_id':''}]);assert len(empty_pair)==2 and all(r['reason']=='empty' for r in empty_pair)
    return {'normal_same_function_allowed':True,'issues':issues,'invalid_id_diagnostics':invalid,'empty_pair_rejected':True}

if __name__=='__main__':
    base=Path(__file__).resolve().parent
    data=json.loads((base/'a025.json').read_text('utf-8'))
    result=verify(data,base)
    print(json.dumps({'id':'A025','passed':True,'result':result},ensure_ascii=True))
