import json,math,statistics as st
rows=json.load(open('rows.json'))
bio={};sm={};rt={}
for s in ('20242025','20252026'):
    for p in json.load(open(f'sk_bios_{s}.json'))['data']: bio[p['playerId']]=p
    for p in json.load(open(f'sk_summary_{s}.json'))['data']: sm.setdefault(p['playerId'],[]).append(p)
    for p in json.load(open(f'sk_realtime_{s}.json'))['data']: rt.setdefault(p['playerId'],[]).append(p)
def feats(pid):
    S=sm.get(pid,[]); R=rt.get(pid,[]); b=bio[pid]
    gp=sum(x['gamesPlayed'] for x in S)
    if gp==0: return None,0
    toi=sum(x['timeOnIcePerGame']*x['gamesPlayed'] for x in S)/gp/60
    h60=lambda k: sum(x[k] for x in R)/max(1,sum(x['timeOnIcePerGame']*x['gamesPlayed'] for x in R)/3600)
    f=dict(isD=1.0 if b['positionCode']=='D' else 0.0,
      ppg=sum(x['points'] for x in S)/gp, gpg=sum(x['goals'] for x in S)/gp, apg=sum(x['assists'] for x in S)/gp,
      spg=sum(x['shots'] for x in S)/gp, toi=toi, hits=h60('hits'), blk=h60('blockedShots'), take=h60('takeaways'), give=h60('giveaways'),
      pim=sum(x['penaltyMinutes'] for x in S)/gp, wgt=b['weight'], pm=sum(x['plusMinus'] for x in S)/gp)
    return f,gp
KEYS=['isD','ppg','gpg','apg','spg','toi','hits','blk','take','give','pim','wgt','pm']
W=dict(isD=3,ppg=2,gpg=1.5,apg=1.5,spg=1,toi=1.5,hits=1,blk=1,take=.7,give=.5,pim=1,wgt=1,pm=.5)
data=[]
for r in rows:
    if r['idx']<3 or not r['pid'] or r['pid'] not in bio: continue
    f,gp=feats(r['pid'])
    if f and gp>=25: data.append((r,f,gp))
mu={k:st.mean(f[k] for _,f,_ in data) for k in KEYS}; sd={k:st.pstdev(f[k] for _,f,_ in data) or 1 for k in KEYS}
def z(f): return [W[k]*(f[k]-mu[k])/sd[k] for k in KEYS]
Z=[(r,z(f)) for r,f,_ in data]
def predict(f,exclude=None,k=12):
    zf=z(f); ds=sorted(((sum((a-b)**2 for a,b in zip(zf,zz)),r) for r,zz in Z if r is not exclude),key=lambda x:x[0])[:k]
    out=[]
    for j in range(14):
        wsum=sum(1/(0.5+d) for d,_ in ds); out.append(sum(r['nib'][j]/(0.5+d) for d,r in ds)/wsum)
    return out,[r['name'] for _,r in ds[:5]]
if __name__=='__main__':
    NIB=['wgt','agi','spd','off','def','pow','chk','hf','stk','acc','end','u11','pas','agg']
    err=[[] for _ in range(14)]; base=[[] for _ in range(14)]
    for r,f,gp in data:
        p,_=predict(f,exclude=r)
        grp=[x for x,ff,_ in data if ff['isD']==f['isD'] and x is not r]
        for j in range(14):
            err[j].append(abs(round(p[j])-r['nib'][j])); base[j].append(abs(round(st.mean(x['nib'][j] for x in grp))-r['nib'][j]))
    print('n',len(data))
    for j in range(14): print(f"{NIB[j]:4} knn {st.mean(err[j]):.2f}  posmean {st.mean(base[j]):.2f}  exact {sum(e==0 for e in err[j])/len(err[j]):.0%}")
