"""
howtoturnpro — leave-one-out validation of salary model v0.7, in the format the site expects.
For each rider with a reported salary, the figure is removed and the model re-estimates him as if it were unknown.
Writes data/validation_loo.csv and data/validation_loo.json (same keys as the v0.4 file, plus band/tier columns).
Run: python3 model/validate_v07.py
"""
import json, os, sys
import pandas as pd
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, f'{ROOT}/model')
import salary_model_v07 as V7

v, stats, base, note = V7.loo(quiet=True)
b = base.set_index('Rider')
rows = []
for _, r in v.iterrows():
    x = b.loc[r['rider']]
    rows.append({'rider': r['rider'], 'team': r['team'], 'age': int(x['age']), 'pts_2026': int(x['pts']),
                 'tier': r['tier'], 'band': r['band'], 'price_year': int(r['price_year']),
                 'reported': int(r['reported']), 'model_loo': int(r['model_loo']),
                 'diff_pct': float(r['diff_pct']), 'ratio': round(r['model_loo'] / r['reported'], 2)})
df = pd.DataFrame(rows)
ab = df['diff_pct'].abs()
worst = df.loc[ab.idxmax()]; best = df.loc[ab.idxmin()]
summary = {
    'n': len(df), 'median_abs_pct': round(ab.median(), 1), 'mean_abs_pct': round(ab.mean(), 1),
    'median_diff_pct': round(df['diff_pct'].median(), 1),
    'within_25': int((ab <= 25).sum()), 'within_40': int((ab <= 40).sum()), 'over_50': int((ab > 50).sum()),
    'under': int((df['diff_pct'] < 0).sum()), 'over': int((df['diff_pct'] > 0).sum()),
    'reported_total_M': round(df['reported'].sum() / 1e6, 1), 'model_total_M': round(df['model_loo'].sum() / 1e6, 1),
    'worst': worst['rider'], 'worst_pct': float(worst['diff_pct']), 'best': best['rider'], 'best_pct': float(best['diff_pct']),
    'model_version': 'v0.8 (22 Sep 2026)',
    'src': 'Gazzetta dello Sport Jan 2026 / Cyclingnews rich list Apr 2025 / Marca Oct 2023 / Cronica Vasca Mar 2024 / '
           'Eurosport-RMC Apr 2024 (Martinez) / NOS Dec 2025 (Kooij) / L\'Equipe Oct 2025 (Vauquelin) / bici.PRO Sep 2025 (Ayuso)',
    'rows': rows,
}
df.to_csv(f'{ROOT}/data/validation_loo.csv', index=False)
json.dump(summary, open(f'{ROOT}/data/validation_loo.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
print({k: summary[k] for k in summary if k != 'rows'})
print(df.sort_values('diff_pct').to_string(index=False))
