#!/usr/bin/env python3
"""
Results Scraper - API PMU officielle
Scrape les résultats réels du Quinté+, les sauvegarde en BDD
et calcule le taux de réussite des prédictions.
À lancer à 21h via cron ou OpenClaw.
"""

import requests
import sqlite3
import json
from datetime import datetime

import os; DB_PATH = os.environ.get("DB_PATH", "/home/h3r7/turf_scraper/turf.db")
HEADERS = {'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json'}

# ============================================================
# API PMU
# ============================================================

def get_programme(date_str):
    """
    Récupère le programme complet du jour via l'API PMU.
    date_str : format DDMMYYYY
    Retourne la liste des réunions avec leurs courses.
    """
    url = f"https://turfinfo.api.pmu.fr/rest/client/1/programme/{date_str}/reunions"
    r = requests.get(url, headers=HEADERS, timeout=15)
    r.raise_for_status()
    data = r.json()
    return data.get("programme", {}).get("reunions", [])


def get_participants(date_str, num_reunion, num_course):
    """
    Récupère les participants + ordreArrivee pour une course donnée.
    ordreArrivee = position finale officielle (0 = non classé/disqualifié)
    """
    url = f"https://turfinfo.api.pmu.fr/rest/client/1/programme/{date_str}/R{num_reunion}/C{num_course}/participants"
    r = requests.get(url, headers=HEADERS, timeout=15)
    r.raise_for_status()
    return r.json().get("participants", [])


def find_quinte(reunions):
    """
    Identifie la course Quinté+ du jour (pariMultiCourses=True ou libelle contient 'PARIS-TURF').
    Retourne (num_reunion, num_course, libelle, hippodrome) ou None.
    """
    for reunion in reunions:
        for course in reunion.get("courses", []):
            libelle = course.get("libelle", "")
            paris_types = [p["typePari"] for p in course.get("paris", [])]
            if any("QUINTE" in p for p in paris_types) or "PARIS-TURF" in libelle:
                return (
                    reunion["numOfficiel"],
                    course["numOrdre"],
                    libelle,
                    reunion["hippodrome"]["libelleCourt"],
                    course.get("arriveeDefinitive", False)
                )
    return None


# ============================================================
# BASE DE DONNÉES
# ============================================================

def init_db_results():
    """Crée les tables si elles n'existent pas encore."""
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()

    # Table results : arrivée officielle
    c.execute('''
        CREATE TABLE IF NOT EXISTS results (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            date TEXT NOT NULL,
            race_name TEXT,
            race_hippodrome TEXT,
            position INTEGER,
            horse_name TEXT,
            odds REAL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')

    # Table performance : comparaison prédictions vs résultats
    c.execute('''
        CREATE TABLE IF NOT EXISTS performance (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            date TEXT NOT NULL,
            race_name TEXT,
            horse_name TEXT,
            predicted_rank INTEGER,
            actual_position INTEGER,
            hit_top5 BOOLEAN,
            hit_winner BOOLEAN,
            source TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')

    conn.commit()
    conn.close()


def save_results(date, race_name, hippodrome, participants):
    """Sauvegarde les positions officielles en BDD (évite les doublons)."""
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    saved = 0

    for p in participants:
        position = p.get("ordreArrivee", 0)
        if position == 0:
            continue  # Non classé / disqualifié
        horse = p.get("nom", "")
        # Cote finale (rapport direct simple gagnant)
        rapport = p.get("dernierRapportDirect", {})
        odds = rapport.get("rapport", 0.0) if rapport else 0.0

        # Vérifier si déjà inséré
        c.execute(
            "SELECT id FROM results WHERE date=? AND race_name=? AND horse_name=? AND position=?",
            (date, race_name, horse, position)
        )
        if c.fetchone():
            continue

        c.execute('''
            INSERT INTO results (date, race_name, race_hippodrome, position, horse_name, odds)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (date, race_name, hippodrome, position, horse, odds))
        saved += c.rowcount

    conn.commit()
    conn.close()
    return saved


def compare_predictions(date, race_name):
    """
    Compare les prédictions du jour avec les résultats réels.
    Retourne un dict avec les stats de performance.
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()

    # Récupérer toutes les prédictions du jour, puis dédoublonner en Python
    # Priorité source : bases > chances > outsiders > partants
    c.execute('''
        SELECT horse_name, prediction_rank, source
        FROM predictions
        WHERE date=? AND source LIKE 'canalturf%'
        ORDER BY prediction_rank ASC, odds ASC
    ''', (date,))
    rows = c.fetchall()

    # Dédoublonner : pour chaque cheval, garder la source la plus précise
    SOURCE_PRIORITY = {
        'canalturf_prono_bases': 1,
        'canalturf_prono_chances': 2,
        'canalturf_prono_outsiders': 3,
        'canalturf_partants': 4,
        'canalturf_selections': 5,
    }
    seen = {}
    for horse, rank, source in rows:
        prio = SOURCE_PRIORITY.get(source, 9)
        if horse not in seen or prio < SOURCE_PRIORITY.get(seen[horse][2], 9):
            seen[horse] = (horse, rank, source)
    predictions = list(seen.values())

    # Récupérer les résultats réels
    c.execute('''
        SELECT horse_name, position
        FROM results
        WHERE date=? AND race_name LIKE ?
        ORDER BY position ASC
    ''', (date, f"%{race_name[:15]}%"))
    results = {row[0]: row[1] for row in c.fetchall()}

    if not results:
        conn.close()
        return None

    # Top 5 réel
    top5_real = {h for h, pos in results.items() if pos <= 5}
    winner_real = next((h for h, pos in results.items() if pos == 1), None)

    # Calcul des hits
    hits_top5 = []
    hits_winner = []
    performance_rows = []

    for horse, pred_rank, source in predictions:
        actual_pos = results.get(horse, 99)
        hit_top5 = horse in top5_real
        hit_winner = horse == winner_real

        if hit_top5:
            hits_top5.append(horse)
        if hit_winner:
            hits_winner.append(horse)

        # Sauvegarder en table performance (structure existante)
        c.execute("SELECT id FROM performance WHERE prediction_date=? AND horse_name=?",
                  (date, horse))
        if not c.fetchone():
            c.execute('''
                INSERT INTO performance
                (prediction_date, race_date, horse_name, predicted_rank, actual_position, hit)
                VALUES (?, ?, ?, ?, ?, ?)
            ''', (date, date, horse, pred_rank, actual_pos, hit_top5))

        performance_rows.append({
            "cheval": horse,
            "pred_rank": pred_rank,
            "actual_pos": actual_pos,
            "hit_top5": hit_top5,
            "hit_winner": hit_winner,
            "source": source
        })

    conn.commit()

    # Stats globales
    bases = [p for p in performance_rows if p["source"] == "canalturf_prono_bases"]
    chances = [p for p in performance_rows if p["source"] == "canalturf_prono_chances"]
    outsiders = [p for p in performance_rows if p["source"] == "canalturf_prono_outsiders"]
    partants = [p for p in performance_rows if p["source"] == "canalturf_partants"]

    nb_pred = len(performance_rows)
    nb_top5 = len(hits_top5)

    stats = {
        "date": date,
        "race_name": race_name,
        "total_predictions": nb_pred,
        "hits_top5": nb_top5,
        "hit_rate_top5": round(nb_top5 / nb_pred * 100, 1) if nb_pred else 0,
        "winner": winner_real,
        "winner_predicted": winner_real in [p["cheval"] for p in performance_rows],
        "bases_hit": [p["cheval"] for p in bases if p["hit_top5"]],
        "bases_miss": [p["cheval"] for p in bases if not p["hit_top5"]],
        "top5_real": sorted([(h, pos) for h, pos in results.items() if pos <= 5], key=lambda x: x[1]),
        "details": performance_rows
    }

    conn.close()
    return stats


# ============================================================
# RAPPORT
# ============================================================

def print_report(stats):
    """Affiche un rapport détaillé en console."""
    if not stats:
        print("❌ Aucune donnée à comparer.")
        return

    print(f"\n{'='*60}")
    print(f"📊 BILAN QUINTÉ+ — {stats['date']}")
    print(f"🏇 {stats['race_name']}")
    print(f"{'='*60}")

    # Arrivée réelle
    print(f"\n🏆 ARRIVÉE OFFICIELLE (Top 5) :")
    for horse, pos in stats["top5_real"]:
        print(f"   {pos}. {horse}")

    # Gagnant prédit ?
    winner = stats["winner"]
    if stats["winner_predicted"]:
        print(f"\n✅ GAGNANT PRÉDIT : {winner}")
    else:
        print(f"\n❌ Gagnant non prédit : {winner}")

    # Bases
    print(f"\n⭐ BASES :")
    for h in stats["bases_hit"]:
        print(f"   ✅ {h} (dans le top 5)")
    for h in stats["bases_miss"]:
        print(f"   ❌ {h} (hors top 5)")

    # Taux de réussite global
    print(f"\n📈 TAUX DE RÉUSSITE : {stats['hit_rate_top5']}% ({stats['hits_top5']}/{stats['total_predictions']} chevaux dans le top 5)")

    # Top 5 favori (cotes les plus basses)
    partants_hits = [p for p in stats["details"] if p["source"] == "canalturf_partants" and p["hit_top5"]]
    print(f"\n💰 FAVORIS PLACÉS : {', '.join([p['cheval'] for p in partants_hits]) or 'aucun'}")

    print(f"{'='*60}\n")


def save_report_json(stats, date):
    """Sauvegarde le rapport en JSON pour archivage."""
    path = f"{os.environ.get('TURF_DIR', '/home/h3r7/turf_scraper')}/perf_{date.replace('-','')}.json"
    with open(path, 'w', encoding='utf-8') as f:
        json.dump(stats, f, indent=2, ensure_ascii=False)
    return path


# ============================================================
# MAIN
# ============================================================

def main():
    today = datetime.now().strftime('%Y-%m-%d')
    date_pmu = datetime.now().strftime('%d%m%Y')

    print(f"\n{'='*60}")
    print(f"🏇 RESULTS SCRAPER — {datetime.now().strftime('%d/%m/%Y %H:%M')}")
    print(f"{'='*60}\n")

    # Init BDD
    init_db_results()

    # Récupérer le programme
    print("📡 Récupération du programme PMU...")
    try:
        reunions = get_programme(date_pmu)
        print(f"   ✅ {len(reunions)} réunion(s) trouvée(s)")
    except Exception as e:
        print(f"   ❌ Erreur API PMU : {e}")
        return

    # Trouver le Quinté+
    quinte = find_quinte(reunions)
    if not quinte:
        print("   ❌ Quinté+ non trouvé dans le programme")
        return

    num_r, num_c, libelle, hippodrome, arrivee_def = quinte
    print(f"   🏇 Quinté+ : R{num_r}C{num_c} — {libelle} ({hippodrome})")
    print(f"   Arrivée définitive : {'✅ OUI' if arrivee_def else '⏳ PAS ENCORE'}")

    if not arrivee_def:
        print("\n⚠️  La course n'est pas encore terminée. Relancez après la course.")
        return

    # Récupérer les participants avec résultats
    print(f"\n📡 Récupération des résultats R{num_r}C{num_c}...")
    try:
        participants = get_participants(date_pmu, num_r, num_c)
        print(f"   ✅ {len(participants)} participants récupérés")
    except Exception as e:
        print(f"   ❌ Erreur : {e}")
        return

    # Trier par position
    classes = sorted(
        [p for p in participants if p.get("ordreArrivee", 0) > 0],
        key=lambda x: x["ordreArrivee"]
    )

    print(f"\n🏆 TOP 5 OFFICIEL :")
    for p in classes[:5]:
        cote = p.get("dernierRapportDirect", {}).get("rapport", "?") if p.get("dernierRapportDirect") else "?"
        print(f"   {p['ordreArrivee']}. {p['nom']:<25} cote={cote}")

    # Sauvegarder les résultats
    saved = save_results(today, libelle, hippodrome, participants)
    print(f"\n💾 {saved} résultats sauvegardés en BDD")

    # Comparer avec les prédictions
    print(f"\n🔍 Comparaison avec les prédictions...")
    stats = compare_predictions(today, libelle)

    if stats:
        print_report(stats)
        path = save_report_json(stats, today)
        print(f"📁 Rapport sauvegardé : {path}")
    else:
        print("⚠️  Aucune prédiction trouvée pour aujourd'hui en BDD.")
        print("   Vérifiez que multi_scraper_v5.py a bien tourné ce matin.")


if __name__ == "__main__":
    main()
