#!/usr/bin/env python3
"""
高效下载：日期扫描 + 精确下载
策略：每7天采样定位联赛活跃期，然后精确获取赔率数据
"""
from __future__ import annotations
import os, sys, json, time, warnings
from pathlib import Path
from datetime import date, timedelta
from collections import defaultdict
import numpy as np
import pandas as pd
import requests

warnings.filterwarnings('ignore')

REPO_ROOT = Path('/root/.openclaw/workspace-flj_bot1/football-predictor-repro')
OUT_DIR = REPO_ROOT / 'historical_data'
OUT_DIR.mkdir(parents=True, exist_ok=True)

API_KEY = os.environ.get('API_FOOTBALL_KEY', '57b64e857ebeffdc156f0c41d43c7894')
API_BASE = os.environ.get('API_FOOTBALL_BASE_URL', 'https://v3.football.api-sports.io').rstrip('/')
HEADERS = {'x-apisports-key': API_KEY}

# 已知的正确联赛ID（通过测试确认）
CORRECT_LEAGUES = {
    'a1':  {'id': 184, 'name': 'A-League'},
    'br1': {'id': 71,  'name': 'Serie A'},
    'd2':  {'id': 59,  'name': '2. Bundesliga'},
    'e0':  {'id': 39,  'name': 'Premier League'},
    'f2':  {'id': 61,  'name': 'Ligue 2'},
    'g1':  {'id': 197, 'name': 'Super League 1'},
    'j1':  {'id': 98,  'name': 'J1 League'},
    'm1':  {'id': 13,  'name': 'Major League Soccer'},
    'r1':  {'id': 235, 'name': 'Premier League'},
    'uz1': {'id': 1023,'name': 'Super League'},
    'k2':  {'id': 292, 'name': 'K League 2'},
}

# 赛季活跃月份
SEASON_MONTHS = {
    'a1':  [10, 11, 12, 1, 2, 3, 4, 5],
    'br1': [4, 5, 6, 7, 8, 9, 10, 11],
    'd2':  [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5],
    'e0':  [8, 9, 10, 11, 12, 1, 2, 3, 4, 5],
    'f2':  [8, 9, 10, 11, 12, 1, 2, 3, 4, 5],
    'g1':  [8, 9, 10, 11, 12, 1, 2, 3, 4, 5],
    'j1':  [2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
    'm1':  [2, 3, 4, 5, 6, 7, 8, 9, 10],
    'r1':  [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5],
    'uz1': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
    'k2':  [2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
}

SEASONS = [2023, 2024, 2025]


def api_get(url, params, sleep=0.5):
    time.sleep(sleep)
    r = requests.get(url, params=params, headers=HEADERS, timeout=60)
    r.raise_for_status()
    return r.json()


def parse_total(bookmakers):
    for bm in bookmakers:
        for bet in bm.get('bets', []):
            if bet.get('name') != 'Goals Over/Under': continue
            local = defaultdict(dict)
            for item in bet.get('values', []):
                raw = item.get('value', '')
                try:
                    odd = float(item.get('odd'))
                    if odd <= 1: continue
                    if raw.startswith('Over '):
                        local[float(raw.replace('Over ', ''))]['over'] = odd
                    elif raw.startswith('Under '):
                        local[float(raw.replace('Under ', ''))]['under'] = odd
                except: pass
            for line, sides in local.items():
                if 'over' in sides and 'under' in sides:
                    return {'ou_line': line, 'over_odds': sides['over'], 'under_odds': sides['under']}
    return None


def parse_1x2(bookmakers):
    rows = []
    for bm in bookmakers:
        for bet in bm.get('bets', []):
            if bet.get('name') != 'Match Winner': continue
            vals = {v.get('value'): v.get('odd') for v in bet.get('values', [])}
            try:
                h, d, a = float(vals.get('Home', 0)), float(vals.get('Draw', 0)), float(vals.get('Away', 0))
                if min(h, a) > 1: rows.append((h, d, a))
            except: pass
    if not rows: return None
    arr = np.array(rows)
    return {'home_odds': float(arr[:,0].mean()), 'draw_odds': float(arr[:,1].mean()), 'away_odds': float(arr[:,2].mean())}


def parse_ah(bookmakers):
    for bm in bookmakers:
        for bet in bm.get('bets', []):
            if bet.get('name') != 'Asian Handicap': continue
            home_odd, away_odd, handicap = None, None, None
            for item in bet.get('values', []):
                raw = item.get('value', '')
                try:
                    odd = float(item.get('odd'))
                    if odd <= 1: continue
                    parts = raw.split()
                    if len(parts) < 2: continue
                    side, hcap = parts[0], float(parts[1])
                    if side == 'Home': home_odd, handicap = odd, hcap
                    elif side == 'Away': away_odd = odd
                except: pass
            if home_odd and away_odd: return handicap, home_odd, away_odd
    return None, None, None


def download_league(code, info):
    lid = info['id']
    print(f"\n{'='*50}\n{code} {info['name']} (id={lid})\n{'='*50}")

    # Step 1: 用日期扫描找出该联赛的比赛日期
    target_ids = {lid}
    active_dates = set()
    league_fixtures = {}  # fixture_id -> fixture data

    for year in SEASONS:
        start = date(year, 1, 1)
        end = date(year, 12, 31)
        current = start
        week = 0
        while current <= end:
            if current.month in SEASON_MONTHS.get(code, []):
                # 每周采样2天(周三+周六)
                for offset in [0, 4]:  # 周三, 周六
                    d = current + timedelta(days=offset)
                    if d.month in SEASON_MONTHS.get(code, []):
                        try:
                            data = api_get(f'{API_BASE}/fixtures', {'date': d.isoformat()})
                            for item in data.get('response', []):
                                if item['league']['id'] in target_ids:
                                    fid = int(item['fixture']['id'])
                                    if fid not in league_fixtures:
                                        st = item['fixture']['status']['short']
                                        hg = item['goals'].get('home')
                                        ag = item['goals'].get('away')
                                        league_fixtures[fid] = {
                                            'fixture_id': fid, 'Date': str(item['fixture']['date'])[:10],
                                            'status': st, 'HomeTeam': item['teams']['home']['name'],
                                            'AwayTeam': item['teams']['away']['name'],
                                            'FTHG': int(hg) if hg is not None else None,
                                            'FTAG': int(ag) if ag is not None else None,
                                            'season': year,
                                        }
                                        active_dates.add(d)
                        except Exception as e:
                            print(f"  扫描{d} ERROR: {e}")
                        time.sleep(0.3)
            current += timedelta(days=7)
        print(f"  {year}: {len(league_fixtures)} fixtures found so far")

    if not league_fixtures:
        print(f"  无fixture数据")
        return 0, 0, 0

    print(f"  扫描完成: {len(league_fixtures)} fixtures")

    # Step 2: 下载赔率
    completed = [f for f in league_fixtures.values() if f['status'] in ['FT', 'AET', 'PEN']]
    completed_ids = sorted([f['fixture_id'] for f in completed])
    print(f"  已完成比赛: {len(completed_ids)}, 下载赔率...")

    odds_rows = []
    for i, fid in enumerate(completed_ids):
        try:
            data = api_get(f'{API_BASE}/odds', {'fixture': fid})
            resp = data.get('response', [])
            bms = resp[0].get('bookmakers', []) if resp else []
            if not bms: continue
            ou = parse_total(bms)
            x1 = parse_1x2(bms)
            ah_h, ah_ho, ah_ao = parse_ah(bms)
            row = {'fixture_id': fid}
            if x1: row.update(x1)
            if ou: row.update({'B365>2.5': ou['over_odds'], 'B365<2.5': ou['under_odds']})
            row['AHh'] = ah_h; row['B365AHH'] = ah_ho; row['B365AHA'] = ah_ao
            odds_rows.append(row)
        except Exception as e:
            pass
        if (i + 1) % 20 == 0:
            print(f"    {i+1}/{len(completed_ids)} ({len(odds_rows)} with odds)")

    # Step 3: 保存
    fix_df = pd.DataFrame(league_fixtures.values())
    odds_df = pd.DataFrame(odds_rows).drop_duplicates(subset=['fixture_id'], keep='last')
    merged = fix_df.merge(odds_df, on='fixture_id', how='left')

    def ftr(row):
        if row['FTHG'] is None or row['FTAG'] is None: return None
        return 'H' if row['FTHG'] > row['FTAG'] else ('A' if row['FTHG'] < row['FTAG'] else 'D')
    merged['FTR'] = merged.apply(ftr, axis=1)

    cols = ['Date', 'HomeTeam', 'AwayTeam', 'FTHG', 'FTAG', 'FTR', 'B365>2.5', 'B365<2.5', 'AHh', 'B365AHH', 'B365AHA', 'season']
    existing = [c for c in cols if c in merged.columns]
    merged[existing].to_csv(OUT_DIR / f'{code}_history.csv', index=False, encoding='utf-8-sig')
    has_ah = merged['AHh'].notna().sum()
    has_ou = merged['B365>2.5'].notna().sum()
    print(f"  保存: {len(merged)}行, AH:{has_ah}, OU:{has_ou}")
    return len(merged), has_ah, has_ou


if __name__ == '__main__':
    print("=" * 50)
    print("高效下载 - 联赛ID修正版")
    print("=" * 50)
    results = {}
    for code, info in sorted(CORRECT_LEAGUES.items(), key=lambda x: x[1]['id']):
        total, ah, ou = download_league(code, info)
        results[code] = {'total': total, 'ah': ah, 'ou': ou}
    print("\n" + "=" * 50)
    print("下载汇总:")
    for code, r in sorted(results.items()):
        print(f"  {code}: {r['total']}行, AH:{r['ah']}, OU:{r['ou']}")
