#!/usr/bin/env python3
"""
用备份的历史数据(原始未取反)训练两个模型
不调用任何外部API
"""
import sys, os, time, json, warnings
import numpy as np
import pandas as pd
import joblib
from pathlib import Path
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score

warnings.filterwarnings('ignore')

REPO = Path('/root/.openclaw/workspace-flj_bot1/football-predictor-repro')
BKUP = Path('/root/backup_football_20260404')
HIST = BKUP / 'historical_data'

V4_OUT = REPO / 'artifacts' / 'v4_models_serving_current'
V4_OUT.mkdir(parents=True, exist_ok=True)

AH1_OUT = REPO / 'models' / 'ah_1year_v3'
AH1_OUT.mkdir(parents=True, exist_ok=True)

def build_v4_features(df):
    """pro_v4特征: AHh正数约定(正数=主队让球=主队强)"""
    f = pd.DataFrame(index=df.index)
    h = df['AHh'].astype(float).values
    ahh = df['B365AHH'].astype(float).values
    aha = df['B365AHA'].astype(float).values
    eps = 1e-9
    f['home_prob'] = aha / (ahh + aha + eps)
    f['prob_diff'] = f['home_prob'] - (ahh / (ahh + aha + eps))
    f['handicap'] = h
    f['ah_ratio'] = ahh / (aha + eps)
    f['water_home'] = 1.0 / (ahh + eps)
    f['water_away'] = 1.0 / (aha + eps)
    f['water_diff'] = f['water_home'] - f['water_away']
    f['hcap_x_water'] = h * f['water_diff']
    return f.fillna(0).replace([np.inf, -np.inf], 0)

def build_ah1_features(df):
    """ah_1year特征"""
    f = pd.DataFrame(index=df.index)
    h = df['AHh'].astype(float).values
    ahh = df['B365AHH'].astype(float).values
    aha = df['B365AHA'].astype(float).values
    eps = 1e-9
    f['home_prob'] = aha / (ahh + aha + eps)
    f['prob_diff'] = f['home_prob'] - 0.5
    f['handicap'] = h
    f['ah_ratio'] = ahh / (aha + eps)
    f['water_home'] = 1.0 / (ahh + eps)
    f['water_away'] = 1.0 / (aha + eps)
    return f.fillna(0).replace([np.inf, -np.inf], 0)

def train_and_eval(df, build_feat_fn):
    """训练+评估, 返回(acc, model_name, total)"""
    if len(df) < 50:
        return None, None, 0
    df = df.copy()
    df['Date'] = pd.to_datetime(df['Date'], dayfirst=True, errors='coerce')
    df = df[df['Date'].notna()].sort_values('Date').reset_index(drop=True)
    split = int(len(df) * 0.75)
    if split < 30 or len(df) - split < 10:
        return None, None, len(df)
    train, test = df.iloc[:split], df.iloc[split:]
    X_all = build_feat_fn(df)
    y_all = (df['FTHG'].astype(float) + df['AHh'].astype(float)) > df['FTAG'].astype(float)
    X_train, y_train = X_all.iloc[:split].values, y_all[:split]
    X_test, y_test = X_all.iloc[split:].values, y_all[split:]
    scaler = StandardScaler()
    X_train_s = scaler.fit_transform(X_train)
    X_test_s = scaler.transform(X_test)
    best_acc, best_pipe, best_name = 0.0, None, ''
    for clf_name, clf in [
        ('GB', GradientBoostingClassifier(n_estimators=100, max_depth=3, random_state=42)),
        ('RF', RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)),
        ('LR', LogisticRegression(C=1.0, max_iter=1000)),
    ]:
        try:
            pipe = Pipeline([('scaler', StandardScaler()), ('clf', clf)])
            pipe.fit(X_train, y_train)
            acc = accuracy_score(y_test, pipe.predict(X_test))
            if acc > best_acc:
                best_acc = acc
                best_pipe = pipe
                best_name = clf_name
        except Exception:
            pass
    if best_pipe is None:
        return None, None, None, len(df)
    return best_acc, best_name, best_pipe, len(df)

print("=" * 60)
print("开始训练 (备份原始历史数据, 不调用API)")
print("=" * 60)

results_v4 = []
files = sorted(HIST.glob('*_history.csv'))
total_files = len(files)
for idx, f in enumerate(files):
    code = f.name.replace('_history.csv', '')
    print(f"[{idx+1}/{total_files}] 处理 {code}...", end=' ')
    try:
        df = pd.read_csv(f, encoding='utf-8-sig', low_memory=False)
        df = df[df['AHh'].notna() & df['B365AHH'].notna() & df['B365AHA'].notna() &
                df['FTHG'].notna() & df['FTAG'].notna()].copy()
        if len(df) < 50:
            print(f"跳过(仅{len(df)}行)")
            continue
        acc, name, pipe, total = train_and_eval(df, build_v4_features)
        if acc is not None:
            feat_cols = list(build_v4_features(df).columns)
            joblib.dump({'pipe': pipe, 'feat_cols': feat_cols},
                        V4_OUT / f'{code}_pro_v4_model.pkl')
            joblib.dump({'accuracy': float(acc), 'model': name, 'total': total,
                        'data': 'backup_original', 'code': code},
                        V4_OUT / f'{code}_pro_v4_config.pkl')
            print(f"✅ {total}场, acc={acc:.1%}")
            results_v4.append({'league': code, 'accuracy': acc, 'total': total})
        else:
            print(f"跳过(训练失败)")
    except Exception as e:
        print(f"❌ {str(e)[:60]}")

print("\n" + "=" * 60)
print("pro_v4 训练完成!")
print("=" * 60)
for r in sorted(results_v4, key=lambda x: x['accuracy'], reverse=True):
    print(f"  {r['league']}: {r['accuracy']:.1%} ({r['total']}场)")
print(f"  总计: {len(results_v4)} 个联赛")

with open(V4_OUT / 'retrain_summary.json', 'w') as f:
    json.dump(results_v4, f, indent=2, ensure_ascii=False)

print("\n模型已保存到 artifacts/v4_models_serving_current/")
