from pathlib import Path
import math
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.ticker import PercentFormatter
R=Path(__file__).resolve().parent
BLUE='#287ba5';ORANGE='#d56b43';GREEN='#44876e';INK='#263545'
plt.rcParams.update({'font.family':'DejaVu Sans','font.size':11,'text.color':INK,'text.parse_math':False,
 'axes.spines.top':False,'axes.spines.right':False,'axes.spines.left':False,'axes.edgecolor':'#ccd6df',
 'figure.facecolor':'#fafbfc','axes.facecolor':'#fafbfc','savefig.facecolor':'#fafbfc'})
def wilson(k,n):
 z=1.96;p=k/n;c=(p+z*z/2/n)/(1+z*z/n);h=z*math.sqrt(p*(1-p)/n+z*z/4/n/n)/(1+z*z/n)
 return c-h,c+h
d=pd.read_csv(R/'transition_groups.csv').query("period == '2023_2025' and axis == 'prior_band'").set_index('value')
order=['<10','10-99','100-999','1000-9999','10000+']
fig,ax=plt.subplots(figsize=(12.5,7.5));fig.subplots_adjust(left=.19,right=.96,top=.76,bottom=.23)
fig.suptitle('Current reception of consecutive games is strongly associated',x=.04,ha='left',y=.97,fontsize=18,fontweight='bold')
fig.text(.04,.90,'2023–2025 follow-ups • one latest qualifying pair per developer • all counts observed September 5, 2026',fontsize=11)
for i,b in enumerate(order):
 r=d.loc[b]
 for col,off,color in [('ge100',-.16,BLUE),('ge1000',.16,ORANGE)]:
  k=int(r[col]);n=int(r.n);v=k/n;lo,hi=wilson(k,n)
  ax.barh(i+off,v,height=.27,color=color,alpha=.9)
  ax.errorbar(v,i+off,xerr=[[v-lo],[hi-v]],fmt='none',color=INK,lw=1,capsize=2)
  ax.text(hi+.015,i+off,f'{k:,}/{n:,}  ({v:.1%})',va='center',fontsize=10)
ax.set_yticks(range(5),['Under 10','10–99','100–999','1,000–9,999','10,000+']);ax.invert_yaxis()
ax.set_ylabel('Previous game’s review count TODAY',labelpad=20);ax.set_xlim(0,1.18);ax.set_xticks([0,.2,.4,.6,.8,1]);ax.xaxis.set_major_formatter(PercentFormatter(1))
ax.set_xlabel('Share of follow-ups reaching the review threshold')
fig.text(.04,.13,'■ Follow-up reaches 100 reviews',color=BLUE,fontweight='bold')
fig.text(.43,.13,'■ Follow-up reaches 1,000 reviews',color=ORANGE,fontweight='bold')
fig.text(.04,.065,'This is an association between current catalog outcomes. It does not measure audience size at the follow-up’s launch.',fontsize=10)
fig.text(.04,.025,'Intervals: descriptive 95% Wilson. Returning developers only; review counts are not sales or a judgment of artistic value.',fontsize=10)
for ext in ['png','svg']:fig.savefig(R/f'followup_reception.{ext}',dpi=160)
plt.close(fig)

fig,axs=plt.subplots(1,2,figsize=(15,6.8));fig.subplots_adjust(left=.10,right=.96,top=.74,bottom=.28,wspace=.50)
fig.suptitle('The whole catalog matters; a long release gap is not a simple reset',x=.035,ha='left',y=.97,fontsize=18,fontweight='bold')
fig.text(.035,.905,'2023–2025 follow-ups • current snapshot outcomes • descriptive comparisons, not causal effects',fontsize=11)
o=pd.read_csv(R/'older_catalog_sensitivity.csv').query("period == '2023_2025' and restriction == 'at_least_third_release'")
for i,flag in enumerate([False,True]):
 r=o[o.older1000.eq(flag)].iloc[0];k=int(r.ge100);n=int(r.n);v=k/n;lo,hi=wilson(k,n)
 axs[0].bar(i,v,width=.55,color=BLUE if flag else '#91a8b6')
 axs[0].errorbar(i,v,yerr=[[v-lo],[hi-v]],fmt='none',color=INK,capsize=4)
 axs[0].text(i,hi+.025,f'{k}/{n:,}\n{v:.1%}',ha='center',fontsize=12)
axs[0].set_xticks([0,1],['No earlier 1,000-review game','An older 1,000-review game'])
axs[0].set_ylim(0,.78);axs[0].yaxis.set_major_formatter(PercentFormatter(1));axs[0].set_ylabel('Follow-up reaches 100 reviews')
axs[0].set_title('When the immediate predecessor has <100 reviews',loc='left',fontsize=12,fontweight='bold',pad=20)
g=pd.read_csv(R/'strong_predecessor_details.csv').query("period == '2023_2025' and restriction == 'all' and axis == 'gap_band'").set_index('value')
bs=['30-180d','181-365d','1-2y','2-4y','4-10y']
for i,b in enumerate(bs):
 r=g.loc[b];k=int(r.ge100);n=int(r.n);v=k/n;lo,hi=wilson(k,n)
 axs[1].errorbar(v,i,xerr=[[v-lo],[hi-v]],fmt='o',color=GREEN,ms=7,capsize=3)
 axs[1].text(1.01,i,f'{k}/{n} ({v:.1%})',va='center',fontsize=10)
axs[1].set_yticks(range(5),['1–6 months','6–12 months','1–2 years','2–4 years','4–10 years']);axs[1].invert_yaxis()
axs[1].set_xlim(.4,1.3);axs[1].set_xticks([.4,.6,.8,1]);axs[1].xaxis.set_major_formatter(PercentFormatter(1))
axs[1].set_title('When the predecessor has 1,000+ reviews',loc='left',fontsize=12,fontweight='bold',pad=20)
axs[1].set_xlabel('Follow-up reaches 100 reviews')
fig.text(.035,.15,'Left: both groups have at least two earlier eligible releases. Right: only developers who returned are observed.',fontsize=11)
fig.text(.035,.09,'Release gaps are not development durations. Older-game strength is measured now, not at the time of the later release.',fontsize=10)
fig.text(.035,.035,'Differences can reflect skills, reputation, scope, resources, publishers and selection. These data do not isolate returning players.',fontsize=10)
for ext in ['png','svg']:fig.savefig(R/f'catalog_context.{ext}',dpi=160)
plt.close(fig)
print('Saved two PNG/SVG figures.')
