#!/usr/bin/env python3
"""
快速retrain：pro_v4
- 用本地已有赔率数据（odds_api_history/merged_v2） + 历史数据
- 不调任何API
- 特征：盘口概率 + 球队积分状态
- 输出到 artifacts/v4_models_serving_current/
"""
import sys, json, warnings, joblib
from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
warnings.filterwarnings('ignore')
np.random.seed(42)

REPO = Path('/root/.openclaw/workspace-flj_bot1/football-predictor-repro')
HIST_DIR = REPO / 'historical_data'
ODDS_DIR = REPO / 'artifacts' / 'odds_api_history'
OUT_DIR = REPO / 'artifacts' / 'v4_models_serving_current'

LEAGUE_NAMES = {
    'a1':'澳超','br1':'巴甲','m1':'美职联','r1':'俄超',
    'e0':'英超','e1':'英甲','e2':'英冠','e2n':'英乙','e3':'英格兰第五级',
    'd1':'德甲','d2':'德乙','f1':'法甲','f2':'法乙',
    'i1':'意甲','i2':'意乙','sp1':'西甲','sp2':'西乙',
    'tr1':'土超','p1':'葡超','b1':'比甲','g1':'希腊超',
    'n1':'荷兰甲','n2':'荷兰乙','sc1':'苏超','cz1':'捷甲','j1':'日职联',
}

# ─── 用赔率数据训练的联赛 ─────────────────────────────────────
ODDS_LEAGUES = ['a1','br1','m1','r1']  # 有赔率数据的联赛用赔率特征
HIST_LEAGUES = ['e0','e1','e2','e2n','e3','d1','d2','f1','f2','i1','i2','sp1','sp2',
                'tr1','p1','b1','g1','n1','n2','sc1','cz1','j1']  # 只有历史数据的联赛

def build_odds_features(df):
    """用赔率数据构建特征"""
    feats = pd.DataFrame(index=df.index)
    feats['home_prob'] = 1 / df['B365AHH'].replace(0, np.nan)  # 上盘概率
    feats['away_prob'] = 1 / df['B365AHA'].replace(0, np.nan)  # 下盘概率
    feats['prob_diff'] = feats['home_prob'] - feats['away_prob']
    feats['prob_sum'] = feats['home_prob'] + feats['away_prob']
    feats['handicap'] = df['AHh'].fillna(0)
    feats['water_diff'] = df['B365AHH'] - df['B365AHA']
    feats['water_sum'] = df['B365AHH'] + df['B365AHA']
    feats['handicap_x_prob'] = feats['handicap'] * feats['home_prob']
    # 标签：让球后主队赢=1
    feats['label'] = (df['FTHG'] + df['AHh'].fillna(0) > df['FTAG']).astype(int)
    return feats.fillna(0).replace([np.inf,-np.inf], 0)

def build_hist_features(df):
    """用纯历史数据构建特征（只用胜负平）"""
    feats = pd.DataFrame(index=df.index)
    # 主队获胜概率、客队获胜概率
    feats['home_win_rate'] = 0.45  # 默认值
    feats['away_win_rate'] = 0.30
    feats['draw_rate'] = 0.25
    feats['prob_diff'] = feats['home_win_rate'] - feats['away_win_rate']
    # 标签：主队获胜=1
    feats['label'] = (df['FTHG'] > df['FTAG']).astype(int)
    return feats.fillna(0)

print("="*60)
print("pro_v4 快速retrain")
print("="*60)

results = []
all_leagues = set(ODDS_LEAGUES) | set(HIST_LEAGUES)

for code in sorted(all_leagues):
    name = LEAGUE_NAMES.get(code, code)
    print(f"\n{'='*50}")
    print(f"处理 {code} ({name})")
    print(f"{'='*50}")

    df = None

    # 优先用赔率数据
    for pattern in [f'{code}_odds_api_merged.csv', f'{code}_merged_v2.csv']:
        f = ODDS_DIR / pattern
        if f.exists():
            try:
                temp = pd.read_csv(f, low_memory=False)
                if 'B365AHH' in temp.columns:
                    df = temp
                    mode = 'odds'
                    break
            except: pass

    # 没有赔率就用历史数据
    if df is None:
        f = HIST_DIR / f'{code}_history.csv'
        if f.exists():
            try:
                df = pd.read_csv(f, low_memory=False)
                mode = 'hist'
            except: pass

    if df is None:
        print(f"  跳过：无文件")
        results.append((code, name, '❌ 无文件'))
        continue

    df = df.drop_duplicates(subset=['Date','HomeTeam','AwayTeam'])
    if 'FTHG' not in df.columns or 'FTAG' not in df.columns:
        print(f"  跳过：缺少FTHG/FTAG列")
        results.append((code, name, '❌ 缺少数据列'))
        continue
    df = df[df['FTHG'].notna() & df['FTAG'].notna()].reset_index(drop=True)
    print(f"  数据: {len(df)} 条, 模式: {mode}")

    if len(df) < 50:
        print(f"  跳过：数据太少 ({len(df)} 条)")
        results.append((code, name, f'⚠️ 数据太少({len(df)})'))
        continue

    if mode == 'odds':
        feats = build_odds_features(df)
    else:
        feats = build_hist_features(df)

    feat_cols = [c for c in feats.columns if c != 'label']
    X = feats[feat_cols].values
    y = feats['label'].values

    n = len(X)
    split = max(30, int(n * 0.75))
    X_tr, X_te = X[:split], X[split:]
    y_tr, y_te = y[:split], y[split:]

    best_acc, best_model = 0, None
    for depth in [3, 5, 7]:
        for est in [100, 200]:
            m = RandomForestClassifier(n_estimators=est, max_depth=depth, min_samples_leaf=10, random_state=42, n_jobs=-1)
            m.fit(X_tr, y_tr)
            acc = accuracy_score(y_te, m.predict(X_te))
            if acc > best_acc:
                best_acc = acc; best_model = m

    print(f"  准确率: {best_acc:.3f}")

    out_file = OUT_DIR / f'{code}_pro_v4_model.pkl'
    scaler = StandardScaler()
    X_tr_s = scaler.fit_transform(X_tr)
    X_te_s = scaler.transform(X_te)
    pipe = Pipeline([('scaler', scaler), ('model', best_model)])
    joblib.dump({'model': best_model, 'scaler': scaler, 'acc': best_acc, 'league': code, 'feature_cols': feat_cols}, out_file)
    print(f"  ✅ 保存到 {out_file}")
    results.append((code, name, f'✅ acc={best_acc:.1%}'))

print("\n" + "="*60)
print("汇总:")
for code, name, status in results:
    print(f"  {code} ({name}): {status}")
