from pathlib import Path
import pandas as pd,numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
R=Path(__file__).resolve().parent;d=pd.read_parquet(R/'game_histories.parquet');m=pd.read_csv(R/'monthly_arrivals.csv');m['date']=pd.to_datetime(m.month)
plt.rcParams.update({'font.family':['DejaVu Sans','Noto Sans CJK TC'],'font.size':10,'axes.spines.top':False,'axes.spines.right':False})
ids=[453270,855860,658700,1608470]
fig,axes=plt.subplots(2,2,figsize=(14,8))
for ax,a in zip(axes.flat,ids):
    g=d[d.appid.eq(a)].iloc[0];x=m[m.appid.eq(a)].sort_values('date');ax.bar(x.date,x['count'],width=24,color='#9bbdc9',alpha=.7);ax.plot(x.date,x['count'].rolling(3,min_periods=1).mean(),color='#286c85',lw=1.5)
    ax.set_title(f"{g['name']} — last 12 full months: {g.last12_count:,} reviews",loc='left',fontweight='bold');ax.set_ylabel('Reviews per calendar month');ax.xaxis.set_major_locator(mdates.YearLocator(2 if len(x)>70 else 1));ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'));ax.tick_params(axis='x',rotation=0)
fig.suptitle('Game lifetimes: continuing activity and later bursts',x=.055,ha='left',fontsize=17,fontweight='bold');fig.text(.055,.018,'Bars: surviving Steam-purchase review arrivals. Line: three-month moving average. Separate vertical scales.\nSelected examples from the random sample; temporal shape does not identify updates, sales, new players, or causes.',fontsize=9,color='#555')
fig.tight_layout(rect=[0,.07,1,.93]);fig.savefig(R/'lifetime_examples.png',dpi=170);fig.savefig(R/'lifetime_examples.svg');plt.close(fig)
# Equal-age 90/365/730-day counts, one row per sampled game with a valid date.
v=d[d.release_clock_valid&d.snapshot_reviews.ge(50)].sort_values('release_d365')
fig,ax=plt.subplots(figsize=(13,8));y=np.arange(len(v))
ax.barh(y,v.release_d90,color='#286c85',label='First 90 days');ax.barh(y,v.release_d365-v.release_d90,left=v.release_d90,color='#bd8555',label='Days 91–365')
ax.set_yticks(y,v['name'],fontsize=7);ax.set_xlabel('Surviving reviews in first 365 days');ax.set_title('A first year contains more than the launch window\nValid recorded dates; sampled games with at least 50 current reviews',loc='left',fontweight='bold');ax.legend(frameon=False,loc='lower right');fig.tight_layout();fig.savefig(R/'first_year_arrivals.png',dpi=170);fig.savefig(R/'first_year_arrivals.svg');plt.close(fig)
