"""Observed JSON-type draft generator, not a full JSON Schema validator or normative inference."""
import json,math,copy,sys
ORDER=['null','boolean','integer','number','string','array','object']
def kind(v):
    if v is None:return 'null'
    if type(v)is bool:return 'boolean'
    if type(v)is int:return 'integer'
    if type(v)is float and math.isfinite(v):return 'number'
    if type(v)is str:return 'string'
    if type(v)is list:return 'array'
    if type(v)is dict:return 'object'
    raise ValueError('JSON-compatible finite values only')
def bound(v,depth=0,counter=None):
    if counter is None:counter=[0]
    counter[0]+=1
    if depth>4 or counter[0]>200:raise ValueError('local depth/node budget')
    k=kind(v)
    if k=='string'and(len(v)>256 or any(0xd800<=ord(c)<=0xdfff for c in v)):raise ValueError('bounded scalar Unicode strings')
    if k=='integer'and abs(v)>2**63-1:raise ValueError('local signed64 sample integer subset, not JSON Schema limit')
    if k in ['array','object']:
        if len(v)>20:raise ValueError('local container budget20')
        if k=='object':
            if any(type(x)is not str or len(x)>64 or any(0xd800<=ord(c)<=0xdfff for c in x)for x in v):raise ValueError('short scalar Unicode property names required')
            values=v.values()
        else:values=v
        for item in values:bound(item,depth+1,counter)
def observe(samples):
    if type(samples)is not list or not 1<=len(samples)<=10 or any(type(s)is not dict for s in samples):raise ValueError('one to ten object samples required')
    for s in samples:bound(s)
    evidence=[];unknown=[]
    def infer(values,path):
        observed=sorted(set(kind(v)for v in values),key=ORDER.index);types=[t for t in observed if not(t=='integer'and 'number'in observed)]
        out={'type':types[0]if len(types)==1 else types}
        objects=[v for v in values if type(v)is dict]
        if objects:
            props={}
            for key in sorted({k for obj in objects for k in obj}):
                present=[obj[key]for obj in objects if key in obj];evidence.append({'path_components':path+[key],'parent_object_samples':len(objects),'present':len(present),'missing':len(objects)-len(present),'nulls':sum(v is None for v in present),'observed_runtime_json_types':sorted(set(kind(v)for v in present),key=ORDER.index)})
                props[key]=infer(present,path+[key])
            out['properties']=props
        arrays=[v for v in values if type(v)is list]
        if arrays:
            items=[v for array in arrays for v in array]
            if items:out['items']=infer(items,path+['[]'])
            else:unknown.append({'path_components':path,'unknown':'only empty arrays observed; items not inferred'})
        return out
    draft={'$schema':'https://json-schema.org/draft/2020-12/schema',**infer(samples,[])}
    return {'draft_schema':draft,'observations':evidence,'unknowns':unknown,'constraints_not_inferred':['required','enum','bounds','additionalProperties=false','authorization','business correctness','real frequency']}
def subset_accepts(schema,v):
    """Only type/properties/items used by this generator. Not standards conformance validation."""
    t=kind(v);allowed=schema.get('type',ORDER);allowed=[allowed]if isinstance(allowed,str)else allowed
    matches=t in allowed or t=='integer'and 'number'in allowed or t=='number'and type(v)is float and v.is_integer()and 'integer'in allowed
    if not matches:return False
    if type(v)is dict:return all(k not in v or subset_accepts(s,v[k])for k,s in schema.get('properties',{}).items())
    if type(v)is list and 'items'in schema:return all(subset_accepts(schema['items'],x)for x in v)
    return True
def demo():
    samples=[{'id':'001','active':True,'amount':None,'tags':[],'meta':{'source':'call'},'unknown_items':[]},{'id':'002','active':False,'amount':0,'tags':['فروش'],'meta':{},'unknown_items':[]},{'id':'003','amount':3.5,'tags':[1],'meta':{'source':None},'unknown_items':[]}]
    before=copy.deepcopy(samples);out=observe(samples);s=out['draft_schema'];p=s['properties']
    assert p['active']=={'type':'boolean'}and p['amount']=={'type':['null','number']}
    assert p['tags']=={'type':'array','items':{'type':['integer','string']}}and p['unknown_items']=={'type':'array'}
    assert p['meta']=={'type':'object','properties':{'source':{'type':['null','string']}}}and not any(k in s for k in ['required','enum','additionalProperties'])
    assert all(subset_accepts(s,x)for x in samples)and subset_accepts(s,{})and subset_accepts(s,{'id':'unseen','extra':'allowed because unspecified'})
    assert not subset_accepts(s,{'active':1})and not subset_accepts(s,{'id':1})and subset_accepts(s,{'unknown_items':[{'previously':'unobserved'}]})
    assert samples==before
    e=next(x for x in out['observations']if x['path_components']==['active']);assert(e['present'],e['missing'],e['nulls'])==(2,1,0)
    rejected=[]
    for name,bad in [('no_samples',[]),('too_many',[{}]*11),('nonfinite',[{'x':float('nan')}]),('non_object',[1])]:
        try:observe(bad)
        except ValueError:rejected.append(name)
        else:raise AssertionError('invalid local sample accepted')
    return {'python_version':sys.version.split()[0],'authored_samples':samples,**out,'narrow_subset_checks':{'all_authored_samples_match':True,'empty_object_matches_no_required_inferred':True,'unseen_id_string_and_extra_property_match':True,'integer_is_not_boolean':True,'id_integer_does_not_match_observed_string':True,'empty_array_items_remain_unspecified':True},'local_invalid_samples_rejected':rejected,'full_json_schema_validator_executed':False,'scope':'Observation-based editable draft using2020-12 type/properties/items only. Stdlib narrow checker not full JSON Schema validator/metaschema/conformance or sample representativeness proof. No external package installed, normative required/enum/bounds/closed-world/auth/business rules inferred, or real API tested.'}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=True,indent=2))
