from pathlib import Path
import numpy as np
import pandas as pd
R=Path(__file__).resolve().parent
def load():return pd.read_parquet(R/'games.parquet'),pd.read_parquet(R/'tags.parquet')
def stats(d):
    z={'n':len(d),'median_reviews':float(d.reviews.median()) if len(d) else None,'median_price':float(d.price.median()) if d.price.notna().any() else None,'low10':int(d.reviews.lt(10).sum())}
    for c in ['h50','r50','r100','r556','r1000','joint']:
        z[c]=int(d[c].sum());z[c+'_rate']=float(d[c].mean()) if len(d) else None
    z['h50_n']=int(d.price.notna().sum())
    z['h50_rate']=float(d.loc[d.price.notna(),'h50'].mean()) if z['h50_n'] else None
    return z
def compare(a,b,cols=('quarter','price_band'),outcomes=('r100','r556','h50','joint'),min_controls=5):
    """Direct standardization: exact strata, nonmembers only; unsupported cases dropped."""
    z={};groups=b.groupby(list(cols),observed=True,dropna=False)
    base=groups[list(outcomes)].mean();base['control_n']=groups.size()
    base=base[base.control_n>=min_controls]
    x=a.merge(base.reset_index(),on=list(cols),suffixes=('','_expected'),how='inner')
    z['supported']=len(x);z['support_rate']=len(x)/len(a) if len(a) else None
    for c in outcomes:
        obs=int(x[c].sum());exp=float(x[c+'_expected'].sum());z[c+'_observed']=obs;z[c+'_expected']=exp;z[c+'_oe']=obs/exp if exp else None
    return z
def save(rows,name):pd.DataFrame(rows).to_csv(R/name,index=False)
def member(t,names,rank):
    sets=[set(t.loc[t.tag.eq(n)&t['rank'].le(rank),'appid']) for n in names]
    return set.intersection(*sets) if sets else set()
