#!/usr/bin/env python3
"""亚盘让球盘模型预测 — 周末比赛"""
import json, warnings
from pathlib import Path
from collections import defaultdict
import pandas as pd
import numpy as np
import joblib
import requests
from datetime import datetime, timedelta

warnings.filterwarnings('ignore')

REPO = Path('/root/.openclaw/workspace-flj_bot1/football-predictor-repro')
HIST = REPO / 'historical_data'
OUT = REPO / 'models' / 'ah_1year_v1'
API_KEY = '57b64e857ebeffdc156f0c41d43c7894'
API_BASE = 'https://v3.football.api-sports.io'

ODDS_AH = ['B365AHH', 'B365AHA', 'AvgAHH', 'AvgAHA', 'PAHH', 'PAHA', 'AHh']
ODDS_OU = ['B365>2.5', 'B365<2.5', 'Avg>2.5', 'Avg<2.5']

LEAGUE_NAMES = {
    'd1':'德甲','d2':'德乙','f1':'法甲','f2':'法乙','cz1':'捷克甲',
    'sc1':'苏超','e1':'英甲','e2':'英冠','e2n':'英乙','e3':'英格兰第五级',
    'i1':'意甲','sp1':'西甲','tr1':'土超','p1':'葡超'
}

LEAGUE_API_IDS = {
    'd1': 78, 'd2': 79, 'f1': 61, 'f2': 62,
    'sc1': 179, 'tr1': 203, 'i1': 135, 'sp1': 140, 'p1': 94,
    # 英超/英冠等暂用placeholder
}

def make_hist():
    return defaultdict(lambda: {
        'gf':[],'ga':[],'tot':[],'win':[],'und':[],
        'gf3':[],'ga3':[],'gf5':[],'ga5':[],'gf10':[],'ga10':[],
        'hgf':[],'hga':[],'hgc':[],'agf':[],'aga':[],'agc':[],'mom':[],'rf':[]
    })

def build_features(df, team_hist):
    rows = []
    for _, m in df.iterrows():
        h, a = str(m['HomeTeam']), str(m['AwayTeam'])
        hh, aa = team_hist[h], team_hist[a]
        fthg = float(m.get('FTHG', 0) or 0) if pd.notna(m.get('FTHG')) else 0
        ftag = float(m.get('FTAG', 0) or 0) if pd.notna(m.get('FTAG')) else 0

        def mn(v, n):
            v = list(v)
            return float(np.mean(v[-n:])) if len(v) >= n else (float(np.mean(v)) if v else 0.0)
        def std(v):
            v = list(v)
            return float(np.std(v[-10:])) if len(v) >= 2 else 0.5

        d = {}
        for p, s in [('home', hh), ('away', aa)]:
            d[f'{p}_gavg'] = np.mean(s['gf']) if s['gf'] else 1.5
            d[f'{p}_gavga'] = np.mean(s['ga']) if s['ga'] else 1.5
            d[f'{p}_tavg'] = np.mean(s['tot']) if s['tot'] else 2.5
            d[f'{p}_winr'] = np.mean(s['win']) if s['win'] else 0.5
            d[f'{p}_undr'] = np.mean(s['und']) if s['und'] else 0.5
            d[f'{p}_gstd'] = std(s.get('gf',[]))
            d[f'{p}_hgf'] = np.mean(s['hgf']) if s['hgf'] else d[f'{p}_gavg']
            d[f'{p}_hga'] = np.mean(s['hga']) if s['hga'] else d[f'{p}_gavga']
            d[f'{p}_hgc'] = np.mean(s['hgc']) if s['hgc'] else 0.3
            d[f'{p}_agf'] = np.mean(s['agf']) if s['agf'] else d[f'{p}_gavg']
            d[f'{p}_aga'] = np.mean(s['aga']) if s['aga'] else d[f'{p}_gavga']
            d[f'{p}_agc'] = np.mean(s['agc']) if s['agc'] else 0.3
            d[f'{p}_mom'] = np.mean(s['mom'][-5:]) if len(s.get('mom',[])) >= 2 else 0.0
            d[f'{p}_rf'] = np.mean(s['rf'][-5:]) if len(s.get('rf',[])) >= 2 else 0.0
            for n in [3, 5, 10]:
                d[f'{p}_gf{n}'] = mn(s.get('gf',[]), n)
                d[f'{p}_ga{n}'] = mn(s.get('ga',[]), n)

        d['hg_diff'] = d['home_gavg'] - d['away_agf']
        d['ga_diff'] = d['home_gavga'] - d['away_aga']
        d['tot_diff'] = d['home_tavg'] - d['away_tavg']
        d['win_diff'] = d['home_winr'] - d['away_winr']
        d['mom_diff'] = d['home_mom'] - d['away_mom']

        for c in ODDS_AH + ODDS_OU:
            v = m.get(c)
            if c == 'AHh':
                d[c] = float(v) if pd.notna(v) else 0.0
            else:
                d[c] = float(v) if pd.notna(v) and float(v) > 1 else 0.0

        b365h = d.get('B365AHH', 0)
        b365a = d.get('B365AHA', 0)
        if b365h > 1 and b365a > 1:
            d['ah_ratio'] = b365h / b365a
            d['ah_prob_home'] = b365a / (b365h + b365a)
        else:
            d['ah_ratio'] = 1.0
            d['ah_prob_home'] = 0.5

        rows.append(d)

        if fthg + ftag > 0 or (pd.notna(m.get('FTHG')) and pd.notna(m.get('FTAG'))):
            for arr in [hh, aa]:
                arr['gf'].append(fthg + ftag); arr['ga'].append(ftag + fthg); arr['tot'].append(fthg + ftag)
                arr['win'].append(1 if fthg > ftag else 0); arr['und'].append(1 if fthg + ftag < 2.5 else 0)
            hh['hgf'].append(fthg); hh['hga'].append(ftag); hh['hgc'].append(1 if ftag == 0 else 0)
            aa['agf'].append(ftag); aa['aga'].append(fthg); aa['agc'].append(1 if fthg == 0 else 0)
            for arr in [hh, aa]:
                g = arr['gf']
                if len(g) >= 2:
                    arr['mom'].append(np.mean(g[-3:]) - np.mean(g[-6:-3]) if len(g) >= 6 else 0)
                    arr['rf'].append(np.mean(arr['win'][-3:]) - np.mean(arr['win'][:-3]) if len(arr['win']) >= 6 else 0)

    return pd.DataFrame(rows) if rows else pd.DataFrame()

def get_upcoming_fixtures(api_id, league_code):
    """获取即将开始的比赛"""
    headers = {'x-apisports-key': API_KEY}
    today = datetime.utcnow()
    
    # 使用 from/to 范围（未来4天=周末）
    params = {
        'league': api_id,
        'season': 2025,
        'from': today.strftime('%Y-%m-%d'),
        'to': (today + timedelta(days=4)).strftime('%Y-%m-%d'),
        'status': 'NS',
        'timezone': 'Asia/Shanghai',
    }
    
    try:
        r = requests.get(f'{API_BASE}/fixtures', params=params, headers=headers, timeout=10)
        data = r.json()
        if data.get('results', 0) > 0:
            return data['response']
    except:
        pass
    
    # 备选：用 next=5
    params2 = {
        'league': api_id,
        'season': 2025,
        'next': 5,
        'timezone': 'Asia/Shanghai',
    }
    try:
        r = requests.get(f'{API_BASE}/fixtures', params=params2, headers=headers, timeout=10)
        data = r.json()
        if data.get('results', 0) > 0:
            return data['response']
    except:
        pass
    
    return []

def predict_league(code):
    config_file = OUT / code / 'optimized_config.json'
    pipeline_file = OUT / code / 'optimized_pipeline.pkl'
    
    if not config_file.exists() or not pipeline_file.exists():
        return None, f"模型文件不存在"

    cfg = json.load(open(config_file))
    pipeline = joblib.load(pipeline_file)

    hist_file = HIST / f'{code}_history.csv'
    if not hist_file.exists():
        return None, "历史数据不存在"
    
    df_hist = pd.read_csv(hist_file, low_memory=False, encoding='utf-8-sig')
    df_hist['Date'] = pd.to_datetime(df_hist['Date'], dayfirst=True, errors='coerce')
    df_hist['FTHG'] = pd.to_numeric(df_hist['FTHG'], errors='coerce')
    df_hist['FTAG'] = pd.to_numeric(df_hist['FTAG'], errors='coerce')
    df_hist = df_hist[df_hist['FTHG'].notna() & df_hist['FTAG'].notna()]
    df_hist = df_hist.sort_values('Date').reset_index(drop=True)

    api_id = LEAGUE_API_IDS.get(code, 0)
    if not api_id:
        return None, f"无API ID"
    
    fixtures = get_upcoming_fixtures(api_id, code)
    if not fixtures:
        return None, f"API无数据"

    # Build team history
    team_hist = make_hist()
    for _, row in df_hist.iterrows():
        h, a = str(row['HomeTeam']), str(row['AwayTeam'])
        hh, aa = team_hist[h], team_hist[a]
        fthg = float(row['FTHG']); ftag = float(row['FTAG'])
        for arr in [hh, aa]:
            arr['gf'].append(fthg + ftag); arr['ga'].append(ftag + fthg); arr['tot'].append(fthg + ftag)
            arr['win'].append(1 if fthg > ftag else 0); arr['und'].append(1 if fthg + ftag < 2.5 else 0)
        hh['hgf'].append(fthg); hh['hga'].append(ftag); hh['hgc'].append(1 if ftag == 0 else 0)
        aa['agf'].append(ftag); aa['aga'].append(fthg); aa['agc'].append(1 if fthg == 0 else 0)
        for arr in [hh, aa]:
            g = arr['gf']
            if len(g) >= 2:
                arr['mom'].append(np.mean(g[-3:]) - np.mean(g[-6:-3]) if len(g) >= 6 else 0)
                arr['rf'].append(np.mean(arr['win'][-3:]) - np.mean(arr['win'][:-3]) if len(arr['win']) >= 6 else 0)

    results = []
    for fix in fixtures:
        f = fix['fixture']
        h = fix['teams']['home']['name']
        a = fix['teams']['away']['name']
        date_str = f['date'][:16].replace('T', ' ')
        
        fake_row = {
            'HomeTeam': h, 'AwayTeam': a,
            'FTHG': np.nan, 'FTAG': np.nan,
            'AHh': 0, 'B365AHH': 0, 'B365AHA': 0,
            'AvgAHH': 0, 'AvgAHA': 0, 'PAHH': 0, 'PAHA': 0,
            'B365>2.5': 0, 'B365<2.5': 0, 'Avg>2.5': 0, 'Avg<2.5': 0
        }
        feat_df = pd.DataFrame([fake_row])
        feat = build_features(feat_df, team_hist).fillna(0).replace([np.inf, -np.inf], 0)
        
        if feat.empty or len(feat.columns) == 0:
            continue
        
        try:
            proba = pipeline.predict_proba(feat.values)[:, 1]
            p_home = float(proba[0])
            p_away = 1 - p_home
            
            th = cfg['threshold']
            side = cfg['side']
            
            if side == 'over':
                bet_home = p_home >= th
                confidence = abs(p_home - th)
            else:
                bet_home = p_home <= th
                confidence = abs(p_away - th)
            
            bet_side = '主队赢让球' if bet_home else '客队赢让球'
            conf_label = '高' if confidence > 0.12 else '中' if confidence > 0.07 else '低'
            
            results.append({
                'date': date_str,
                'home': h,
                'away': a,
                'p_home': p_home,
                'p_away': p_away,
                'bet': bet_side,
                'conf': conf_label,
                'confidence': confidence,
                'th': th,
                'side': side,
                'wf_acc': cfg.get('wf_bet_acc', cfg.get('bet_acc', 0))
            })
        except Exception as e:
            pass

    return results, None

# 只预测有正确API数据的联赛
TARGET_LEAGUES = ['d1','d2','f1','f2','sc1','tr1','i1','sp1','p1']

print("=== 亚盘让球盘 — 周末比赛预测 ===\n")

all_preds = {}
for code in TARGET_LEAGUES:
    name = LEAGUE_NAMES.get(code, code)
    preds, err = predict_league(code)
    if err:
        print(f"【{name}】{err}")
    elif preds:
        all_preds[code] = {'name': name, 'predictions': preds}
        print(f"\n【{name}】")
        for p in preds:
            print(f"  {p['date']} {p['home']} vs {p['away']}")
            print(f"    主队赢AH概率: {p['p_home']:.1%} | 投注: {p['bet']} | 信心: {p['conf']}")
    else:
        print(f"\n【{name}】无预测结果")

# 只显示高信心投注
print("\n\n=== 高信心投注汇总 ===")
for code, info in all_preds.items():
    high_conf = [p for p in info['predictions'] if p['conf'] == '高']
    if high_conf:
        print(f"\n【{info['name']}】")
        for p in high_conf:
            wf = p['wf_acc']
            print(f"  {p['date']} {p['home']}({p['p_home']:.0%}) vs {p['away']}({p['p_away']:.0%}) → {p['bet']} (信心:{p['conf']}, WF准确率:{wf:.0%})")
