#!/usr/bin/env python3
"""
Exp06: ConvNext OOF Score Calculation

Calculate accurate OOF score for ConvNext model to replace the estimated ~0.61.
This will complete our understanding of all 3 models' true performance.
"""

import pandas as pd
import numpy as np

print("="*70)
print("🚀 Exp06: ConvNext OOF Score Calculation")
print("="*70)
print("Purpose: Calculate accurate OOF score for ConvNext model")
print("="*70)

# Load ConvNext OOF predictions
print("\n📦 Loading ConvNext OOF predictions...")
convnext_oof = pd.read_csv('/kaggle/input/csiro-model-ensembles-lb-0-634/Model_3_ConvNeXt_pred.csv')
print(f"✅ Loaded OOF predictions: {len(convnext_oof)} images")
print(f"Columns: {convnext_oof.columns.tolist()}")

# Competition settings
ROOT = "/kaggle/input/csiro-biomass/"
LABELS = ['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g', 'Dry_Total_g', 'GDM_g']
WEIGHTS = {'Dry_Green_g': 0.1, 'Dry_Dead_g': 0.1, 'Dry_Clover_g': 0.1, 'GDM_g': 0.2, 'Dry_Total_g': 0.5}

# Load ground truth
print("\n📊 Loading ground truth...")
train_df = pd.read_csv(ROOT + "train.csv")
train_wide = train_df.pivot_table(
    index='image_path',
    columns='target_name',
    values='target',
    aggfunc='first'
).reset_index()
print(f"✅ Loaded training data: {len(train_wide)} images")

# Merge predictions with ground truth
print("\n🔗 Merging predictions with ground truth...")
merged = pd.merge(convnext_oof, train_wide, on='image_path', suffixes=('', '_true'))
print(f"✅ Merged {len(merged)} images")

# Extract predictions and ground truth
y_pred = merged[LABELS].values
y_true = merged[[f'{col}_true' for col in LABELS]].values

# Calculate competition metric (weighted R²)
print("\n" + "="*70)
print("📊 Calculating Competition Metric (Weighted R²)...")
print("="*70)

weights_array = np.array([WEIGHTS[l] for l in LABELS])
y_weighted_mean = np.average(y_true, weights=weights_array, axis=1).mean()
ss_res = np.average((y_true - y_pred)**2, weights=weights_array, axis=1).mean()
ss_tot = np.average((y_true - y_weighted_mean)**2, weights=weights_array, axis=1).mean()
oof_score = 1 - ss_res / ss_tot

print(f"\n🎯 ConvNext OOF Score: {oof_score:.6f}")
print("="*70)

# Per-target breakdown
print("\n📊 Per-Target R² Scores:")
print("-" * 70)
for i, label in enumerate(LABELS):
    y_mean = y_true[:, i].mean()
    ss_res_target = ((y_true[:, i] - y_pred[:, i])**2).mean()
    ss_tot_target = ((y_true[:, i] - y_mean)**2).mean()
    r2_target = 1 - ss_res_target / ss_tot_target
    print(f"  {label:20s}: {r2_target:.6f}")

# Save detailed results
print("\n💾 Saving results...")
with open('exp06_convnext_oof_score.txt', 'w') as f:
    f.write(f"Exp06: ConvNext OOF Score Calculation\n")
    f.write(f"=" * 70 + "\n\n")
    f.write(f"Overall OOF Score (Weighted R²): {oof_score:.6f}\n\n")
    f.write(f"Per-Target R² Scores:\n")
    for i, label in enumerate(LABELS):
        y_mean = y_true[:, i].mean()
        ss_res_target = ((y_true[:, i] - y_pred[:, i])**2).mean()
        ss_tot_target = ((y_true[:, i] - y_mean)**2).mean()
        r2_target = 1 - ss_res_target / ss_tot_target
        f.write(f"  {label:20s}: {r2_target:.6f}\n")
    f.write(f"\n" + "=" * 70 + "\n")
    f.write(f"\nComparison with other models:\n")
    f.write(f"  DINOv2 OOF:  0.6847\n")
    f.write(f"  ConvNext OOF: {oof_score:.6f}\n")
    f.write(f"  SigLIP OOF:  0.5953\n")

print("✅ Results saved to exp06_convnext_oof_score.txt")

# Summary
print("\n" + "="*70)
print("📊 Summary")
print("="*70)
print(f"ConvNext OOF Score: {oof_score:.6f}")
print(f"\nModel Ranking:")
print(f"  1. DINOv2:   0.6847")
print(f"  2. ConvNext: {oof_score:.6f}")
print(f"  3. SigLIP:   0.5953")
print("="*70)

print("\n✨ Exp06 Complete!")
