"""Explicitly exploratory checks motivated by the first continuation results."""
from common import *
d,t=load()
recent=d[d.paid&d.year.isin([2025,2026])&d.month.le(8)].copy()
outside=recent[recent.strict&~recent[['deck','action','auto','tower']].any(axis=1)]
joined=t[t['rank'].le(10)].merge(outside[['appid','year']].reset_index(drop=True),on='appid')
outside_tags=joined.groupby(['tag','year']).size().unstack(fill_value=0)
outside_tags['delta']=outside_tags[2026]-outside_tags[2025]
outside_tags.sort_values('delta',ascending=False).to_csv(R/'outside_four_tags.csv')
rows=[]
for axis in ['price_bucket','text_bucket']:
    for (year,value),x in recent.groupby(['year',axis],dropna=False):
        rows.append(dict(axis=axis,year=year,value=value,eligible=len(x),builds=int(x.strict.sum()),share=float(x.strict.mean())))
pd.DataFrame(rows).to_csv(R/'growth_price_text.csv',index=False)
creators=[]
for year in [2025,2026]:
    x=recent[recent.year.eq(year)&recent.strict]
    for field in ['developer_key','publisher_key']:
        groups=x.groupby(field).size().sort_values(ascending=False)
        creators.append(dict(year=year,role=field,builds=len(x),unique=int(groups.size),top1_games=int(groups.iloc[0]),top10_games=int(groups.head(10).sum()),top10_share=float(groups.head(10).sum()/len(x))))
pd.DataFrame(creators).to_csv(R/'growth_creator_concentration.csv',index=False)

# Standardize the build-match rate to the same 2025 text-length distribution.
# This checks a mechanical opportunity to match more words, not copywriting effects.
textrows=[]
for year in [2025,2026]:
    x=recent[recent.year.eq(year)]
    rates=x.groupby('text_bucket').strict.mean()
    weights=recent[recent.year.eq(2025)].text_bucket.value_counts(normalize=True)
    textrows.append(dict(year=year,raw_build_share=float(x.strict.mean()),standardized_to_2025_text_length=float((rates*weights).sum())))
pd.DataFrame(textrows).to_csv(R/'growth_text_standardized.csv',index=False)

# Recheck deck results with the already-existing direct deck-language signal.
textdeck=[]
for period in ['2025','2026_H1','2026_JulAug']:
    pool=d[d.build&d.period.eq(period)]
    e=expected(pool,pool.reviews.ge(100)&pool.positive_pct.ge(80))
    for value in [True,False]:
        x=pool[pool.deck&pool.card_deck.eq(value)];den=e.reindex(x.index).sum()
        textdeck.append(dict(period=period,deck_language=value,**stats(x),joint_ratio=float((x.reviews.ge(100)&x.positive_pct.ge(80)).sum()/den)))
pd.DataFrame(textdeck).to_csv(R/'deck_language_sensitivity.csv',index=False)

# Inspect every inventory-tag case. These are advertised mechanics, not gameplay
# verification. Labels were assigned after aggregate inventory outcomes were seen.
LABELS={
2468550:('jewel_party',False),2500460:('packing_items_aliens',True),2686020:('custom_card_components',False),
2916670:('match3_residents',False),3177890:('farm_cards',False),3215240:('ordered_probabilistic_skills',False),
3296910:('drafted_loot_cards',False),3325030:('weapon_modifications',False),3410180:('equipment_sets',False),
3470920:('card_inventory_capacity',False),3573070:('toy_table_layout',True),3665300:('party_card_slots',False),
4026180:('employee_scoring_cards',False),2652600:('item_formations_links',True),3284290:('spatial_card_cost',True),
3327710:('rpg_equipment',False),3355940:('custom_card_components',False),3481020:('poker_chips',False),
3802470:('inventory_grid_interactions',True),3941130:('card_stack_triggered_items',False),4047130:('roulette_card_rules',False),
4180100:('rpg_autobattle_collectibles',False),4206270:('wired_module_board',True),3380700:('wired_inventory_grid',True),
4092940:('magazine_bullets',False),4474960:('cooking_production',False),4537600:('dice_triggered_weapons',False)}
inv_ids=set(t.loc[t.tag.eq('Inventory Management'),'appid'])
x=d[d.build&d.deck&d.period.ne('other')&d.index.isin(inv_ids)].copy()
assert set(x.index)==set(LABELS)
x['manual_mechanic']=[LABELS[a][0] for a in x.index]
x['spatial_layout_pitch']=[LABELS[a][1] for a in x.index]
x[['appid','name','period','reviews','positive_pct','usd_list_price','manual_mechanic','spatial_layout_pitch','short_description','description','store_url']].to_parquet(R/'inventory_audit.parquet',index=False)
inventory=[]
for period in ['2025','2026_H1','2026_JulAug','combined']:
    p=x if period=='combined' else x[x.period.eq(period)]
    for flag in [True,False]:
        inventory.append(dict(period=period,spatial_layout_pitch=flag,**stats(p[p.spatial_layout_pitch.eq(flag)])))
pd.DataFrame(inventory).to_csv(R/'inventory_audit_results.csv',index=False)

# Preserve individual evidence for a mixed-response case gallery.
ids=[3284290,3355940,2686020,2652600,3802470,4206270,3380700,4537600,2500460,3573070,
     3610530,3703380,3333700,3509430,4332200,3816000,4730540,3509230]
gallery=d[d.index.isin(ids)][['appid','name','first_date','period','reviews','positive_pct','usd_list_price','short_description','description','store_url']]
gallery.to_csv(R/'case_gallery.csv',index=False)
print('GROWTH BY PRICE/TEXT\n',pd.DataFrame(rows).round(3).to_string(index=False))
print('CREATORS\n',pd.DataFrame(creators).round(3).to_string(index=False))
print('TEXT STANDARDIZATION\n',pd.DataFrame(textrows).round(4).to_string(index=False))
print('DECK LANGUAGE\n',pd.DataFrame(textdeck)[['period','deck_language','n','ge100','liked100','joint_ratio']].round(3).to_string(index=False))
print('INVENTORY AUDIT\n',pd.DataFrame(inventory)[['period','spatial_layout_pitch','n','ge100','liked100']].to_string(index=False))
print('GALLERY\n',gallery[['appid','name','first_date','reviews','positive_pct','usd_list_price']].to_string(index=False))
