#!/usr/bin/env python3
"""
Scoring Engine - Analyse complète des partants via API PMU
Calcule un score composite et recommande Simple Gagnant, Simple Placé, Couplé
Sauvegarde en BDD + JSON + rapport Telegram
"""

import requests
import sqlite3
import json
import re
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'}

# ============================================================
# DÉCODEUR MUSIQUE
# ============================================================

def parse_musique(musique):
    """
    Décode la musique PMU : ex "1a0a(25)0a4a2a"
    Retourne des stats sur les 10 dernières courses (hors recul)
    Position 1 = course la plus récente
    """
    if not musique:
        return {}

    # Supprimer les indices de recul (25), (24) etc.
    clean = re.sub(r'\(\d+\)', '', musique)

    # Extraire les résultats : chiffre + lettre discipline
    # a=attelé, m=monté, p=plat, h=haies, s=steeple, c=cross
    resultats = re.findall(r'(\d+|D|0)([amphsc]?)', clean)

    positions = []
    for pos, disc in resultats[:10]:  # 10 dernières
        if pos == 'D':
            positions.append(99)  # Disqualifié
        else:
            positions.append(int(pos))

    if not positions:
        return {}

    # Stats
    nb_courses = len(positions)
    nb_victoires = positions.count(1)
    nb_places = sum(1 for p in positions if 1 <= p <= 3)
    nb_top5 = sum(1 for p in positions if 1 <= p <= 5)
    nb_disq = positions.count(99)

    # Forme récente (3 dernières)
    recentes = [p for p in positions[:3] if p != 99]
    forme_recente = sum(recentes) / len(recentes) if recentes else 99

    # Tendance : amélioration ou dégradation
    if len(positions) >= 4:
        debut = sum(positions[-4:]) / 4  # anciennes
        fin   = sum(positions[:4])  / 4  # récentes
        tendance = debut - fin  # positif = amélioration
    else:
        tendance = 0

    return {
        'positions':      positions,
        'nb_courses':     nb_courses,
        'nb_victoires':   nb_victoires,
        'nb_places':      nb_places,
        'nb_top5':        nb_top5,
        'nb_disq':        nb_disq,
        'forme_recente':  round(forme_recente, 1),
        'tendance':       round(tendance, 1),
        'tx_victoire':    round(nb_victoires / nb_courses * 100, 1) if nb_courses else 0,
        'tx_place':       round(nb_places / nb_courses * 100, 1) if nb_courses else 0,
    }


# ============================================================
# SCORING COMPOSITE
# ============================================================

def score_cheval(p, all_participants):
    """
    Calcule un score composite 0-100 pour un cheval.
    Critères pondérés :
      - Cote (20%) : inverse de la cote = plus c'est bas, mieux c'est
      - Forme récente (25%) : positions des 3 dernières courses
      - Taux victoire carrière (15%)
      - Taux placé carrière (15%)
      - Réduction kilométrique (10%) : vitesse de référence
      - Tendance (10%) : amélioration récente
      - Avis entraîneur (5%)
    """
    score = 0
    details = {}

    # 1. COTE (20 pts) — plus la cote est basse, plus le cheval est favori
    cote = 0
    rapport = p.get('dernierRapportDirect', {})
    if rapport:
        cote = rapport.get('rapport', 0)
    if not cote:
        rapport_ref = p.get('dernierRapportReference', {})
        cote = rapport_ref.get('rapport', 99) if rapport_ref else 99

    # Normaliser : cote 1 = 20pts, cote 10 = 10pts, cote 50+ = 2pts
    if cote > 0:
        score_cote = max(2, min(20, 20 / (1 + cote * 0.15)))
    else:
        score_cote = 2
    score += score_cote
    details['cote'] = round(cote, 1)
    details['score_cote'] = round(score_cote, 1)

    # 2. FORME RÉCENTE (25 pts)
    musique_stats = parse_musique(p.get('musique', ''))
    forme = musique_stats.get('forme_recente', 99)
    if forme <= 1:
        score_forme = 25
    elif forme <= 2:
        score_forme = 20
    elif forme <= 3:
        score_forme = 15
    elif forme <= 5:
        score_forme = 10
    elif forme <= 8:
        score_forme = 5
    else:
        score_forme = 0
    score += score_forme
    details['forme_recente'] = forme
    details['score_forme'] = score_forme

    # 3. TAUX VICTOIRE CARRIÈRE (15 pts)
    nb_courses_total = p.get('nombreCourses', 0)
    nb_victoires_total = p.get('nombreVictoires', 0)
    tx_vic = (nb_victoires_total / nb_courses_total * 100) if nb_courses_total else 0
    score_vic = min(15, tx_vic * 0.5)
    score += score_vic
    details['tx_victoire'] = round(tx_vic, 1)
    details['score_victoire'] = round(score_vic, 1)

    # 4. TAUX PLACÉ CARRIÈRE (15 pts)
    nb_places_total = p.get('nombrePlaces', 0)
    tx_place = (nb_places_total / nb_courses_total * 100) if nb_courses_total else 0
    score_place = min(15, tx_place * 0.2)
    score += score_place
    details['tx_place'] = round(tx_place, 1)
    details['score_place'] = round(score_place, 1)

    # 5. RÉDUCTION KILOMÉTRIQUE (10 pts) — plus c'est bas, plus c'est rapide
    rk = p.get('reductionKilometrique', 0)
    if rk > 0:
        # Normaliser : RK 72000 = excellent, RK 78000 = moyen
        all_rk = [x.get('reductionKilometrique', 0) for x in all_participants if x.get('reductionKilometrique', 0) > 0]
        if all_rk:
            min_rk = min(all_rk)
            max_rk = max(all_rk)
            if max_rk > min_rk:
                score_rk = 10 * (1 - (rk - min_rk) / (max_rk - min_rk))
            else:
                score_rk = 5
        else:
            score_rk = 5
    else:
        score_rk = 0
    score += score_rk
    details['rk'] = rk
    details['score_rk'] = round(score_rk, 1)

    # 6. TENDANCE (10 pts) — amélioration récente
    tendance = musique_stats.get('tendance', 0)
    score_tendance = min(10, max(0, 5 + tendance))
    score += score_tendance
    details['tendance'] = tendance
    details['score_tendance'] = round(score_tendance, 1)

    # 7. AVIS ENTRAÎNEUR (5 pts)
    avis = p.get('avisEntraineur', 'NEUTRE')
    score_avis = {'POSITIF': 5, 'TRES_POSITIF': 5, 'NEUTRE': 2, 'NEGATIF': 0, 'TRES_NEGATIF': 0}.get(avis, 2)
    score += score_avis
    details['avis_entraineur'] = avis
    details['score_avis'] = score_avis

    # Bonus driver change négatif
    if p.get('driverChange', False):
        score -= 3
        details['driver_change'] = True

    details['score_total'] = round(score, 1)
    details['musique'] = p.get('musique', '')
    details['nb_victoires'] = nb_victoires_total
    details['nb_places'] = nb_places_total
    details['nb_courses'] = nb_courses_total

    return round(score, 1), details


# ============================================================
# RECOMMANDATIONS PARIS
# ============================================================

def build_recommendations(scored_horses):
    """
    Construit les recommandations de paris basées sur le scoring.
    """
    # Trier par score décroissant
    ranked = sorted(scored_horses, key=lambda x: x['score'], reverse=True)

    top1 = ranked[0]
    top2 = ranked[1]
    top3 = ranked[2]

    # Calcul de la confiance
    def confiance(score):
        if score >= 55:   return "🔥 FORTE"
        elif score >= 45: return "✅ BONNE"
        elif score >= 35: return "⚠️  MOYENNE"
        else:             return "❓ FAIBLE"

    reco = {
        'simple_gagnant': {
            'cheval':     top1['nom'],
            'numero':     top1['numero'],
            'cote':       top1['details']['cote'],
            'score':      top1['score'],
            'confiance':  confiance(top1['score']),
            'mise_suggeree': 2.0,
            'gain_potentiel': round(2.0 * top1['details']['cote'], 2),
            'justification': _justif_gagnant(top1),
        },
        'simple_place': {
            'cheval':     top1['nom'],
            'numero':     top1['numero'],
            'cote':       round(top1['details']['cote'] / 4, 2),  # Cote placé ≈ cote/4
            'score':      top1['score'],
            'confiance':  confiance(top1['score'] + 10),  # Placé plus facile
            'mise_suggeree': 3.0,
            'gain_potentiel': round(3.0 * (top1['details']['cote'] / 4), 2),
            'justification': 'Même cheval qu\'en Simple Gagnant, pari sécurisé',
        },
        'couple_gagnant': {
            'cheval1':    top1['nom'],
            'numero1':    top1['numero'],
            'cheval2':    top2['nom'],
            'numero2':    top2['numero'],
            'score_combo': round((top1['score'] + top2['score']) / 2, 1),
            'confiance':  confiance((top1['score'] + top2['score']) / 2 - 5),
            'mise_suggeree': 2.0,
            'justification': _justif_couple(top1, top2),
        },
        'couple_place': {
            'cheval1':    top1['nom'],
            'numero1':    top1['numero'],
            'cheval2':    top3['nom'],
            'numero2':    top3['numero'],
            'score_combo': round((top1['score'] + top3['score']) / 2, 1),
            'confiance':  confiance((top1['score'] + top3['score']) / 2),
            'mise_suggeree': 2.0,
            'justification': 'Combinaison favorite + outsider solide',
        },
        'top3_scores': [
            {'rang': i+1, 'nom': h['nom'], 'numero': h['numero'],
             'score': h['score'], 'cote': h['details']['cote'],
             'forme': h['details']['forme_recente'],
             'tx_vic': h['details']['tx_victoire'],
             'avis': h['details']['avis_entraineur'],
             'musique': h['details']['musique']}
            for i, h in enumerate(ranked[:5])
        ],
        'budget_total': 9.0,
        'generated_at': datetime.now().isoformat(),
    }

    return reco


def _justif_gagnant(horse):
    parts = []
    d = horse['details']
    if d['forme_recente'] <= 2:
        parts.append(f"forme excellente ({d['forme_recente']} de moy.)")
    if d['tx_victoire'] >= 20:
        parts.append(f"bon taux de victoire ({d['tx_victoire']}%)")
    if d['avis_entraineur'] == 'POSITIF':
        parts.append("avis entraîneur positif")
    if d['tendance'] > 2:
        parts.append("en progression")
    if d['cote'] <= 5:
        parts.append(f"grand favori ({d['cote']}/1)")
    return " • ".join(parts) if parts else "Meilleur score composite"


def _justif_couple(h1, h2):
    return f"{h1['nom']} (score {h1['score']}) + {h2['nom']} (score {h2['score']})"


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

def init_scoring_table():
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute('''
        CREATE TABLE IF NOT EXISTS scoring (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            date TEXT NOT NULL,
            race_name TEXT,
            horse_name TEXT,
            horse_number INTEGER,
            score REAL,
            score_cote REAL,
            score_forme REAL,
            score_victoire REAL,
            score_place REAL,
            score_rk REAL,
            score_tendance REAL,
            score_avis REAL,
            cote REAL,
            forme_recente REAL,
            tx_victoire REAL,
            tx_place REAL,
            avis_entraineur TEXT,
            musique TEXT,
            rang_scoring INTEGER,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    c.execute('''
        CREATE TABLE IF NOT EXISTS recommendations (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            date TEXT NOT NULL,
            race_name TEXT,
            type_pari TEXT,
            cheval1 TEXT,
            numero1 INTEGER,
            cheval2 TEXT,
            numero2 INTEGER,
            cote REAL,
            mise REAL,
            gain_potentiel REAL,
            confiance TEXT,
            justification TEXT,
            resultat TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    conn.commit()
    conn.close()


def save_scoring(date, race_name, scored_horses, recommendations):
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()

    # Supprimer les anciens scores du jour
    c.execute("DELETE FROM scoring WHERE date=? AND race_name=?", (date, race_name))
    c.execute("DELETE FROM recommendations WHERE date=? AND race_name=?", (date, race_name))

    # Sauvegarder les scores
    ranked = sorted(scored_horses, key=lambda x: x['score'], reverse=True)
    for rang, h in enumerate(ranked, 1):
        d = h['details']
        c.execute('''
            INSERT INTO scoring
            (date, race_name, horse_name, horse_number, score, score_cote, score_forme,
             score_victoire, score_place, score_rk, score_tendance, score_avis,
             cote, forme_recente, tx_victoire, tx_place, avis_entraineur, musique, rang_scoring)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        ''', (date, race_name, h['nom'], h['numero'], h['score'],
              d['score_cote'], d['score_forme'], d['score_victoire'],
              d['score_place'], d['score_rk'], d['score_tendance'], d['score_avis'],
              d['cote'], d['forme_recente'], d['tx_victoire'], d['tx_place'],
              d['avis_entraineur'], d['musique'], rang))

    # Sauvegarder les recommandations
    paris = [
        ('simple_gagnant', recommendations['simple_gagnant']),
        ('simple_place',   recommendations['simple_place']),
        ('couple_gagnant', recommendations['couple_gagnant']),
        ('couple_place',   recommendations['couple_place']),
    ]
    for type_pari, reco in paris:
        c1 = reco.get('cheval', reco.get('cheval1', ''))
        n1 = reco.get('numero', reco.get('numero1', 0))
        c2 = reco.get('cheval2', '')
        n2 = reco.get('numero2', 0)
        c.execute('''
            INSERT INTO recommendations
            (date, race_name, type_pari, cheval1, numero1, cheval2, numero2,
             cote, mise, gain_potentiel, confiance, justification)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
        ''', (date, race_name, type_pari, c1, n1, c2, n2,
              reco.get('cote', 0), reco.get('mise_suggeree', 2),
              reco.get('gain_potentiel', 0),
              reco.get('confiance', ''), reco.get('justification', '')))

    conn.commit()
    conn.close()


# ============================================================
# RAPPORT CONSOLE + JSON
# ============================================================

def print_report(scored_horses, recommendations, race_info):
    ranked = sorted(scored_horses, key=lambda x: x['score'], reverse=True)
    race_name = race_info.get('nom', 'Quinté+')
    hippodrome = race_info.get('hippodrome', '')
    heure = race_info.get('heure', '')

    print(f"\n{'='*65}")
    print(f"🏇 SCORING — {race_name}")
    print(f"   {hippodrome} — {heure}")
    print(f"{'='*65}")
    print(f"  {'RANG':<5} {'N°':<4} {'CHEVAL':<25} {'SCORE':<7} {'COTE':<7} {'FORME':<7} {'TX-V':<6} {'AVIS'}")
    print(f"{'─'*65}")

    for rang, h in enumerate(ranked, 1):
        d = h['details']
        star = '⭐' if rang <= 3 else '  '
        print(f"  {star}{rang:<4} {h['numero']:<4} {h['nom']:<25} {h['score']:<7} {d['cote']:<7} {d['forme_recente']:<7} {d['tx_victoire']:<6}% {d['avis_entraineur']}")

    print(f"\n{'='*65}")
    print(f"💰 RECOMMANDATIONS PARIS")
    print(f"{'='*65}")

    sg = recommendations['simple_gagnant']
    print(f"\n  🎯 SIMPLE GAGNANT")
    print(f"     ➤ N°{sg['numero']} {sg['cheval']} @ {sg['cote']}/1")
    print(f"     Mise : {sg['mise_suggeree']}€ | Gain potentiel : {sg['gain_potentiel']}€")
    print(f"     Confiance : {sg['confiance']}")
    print(f"     {sg['justification']}")

    sp = recommendations['simple_place']
    print(f"\n  🛡️  SIMPLE PLACÉ")
    print(f"     ➤ N°{sp['numero']} {sp['cheval']} @ {sp['cote']}/1")
    print(f"     Mise : {sp['mise_suggeree']}€ | Gain potentiel : {sp['gain_potentiel']}€")
    print(f"     Confiance : {sp['confiance']}")

    cg = recommendations['couple_gagnant']
    print(f"\n  🔗 COUPLÉ GAGNANT")
    print(f"     ➤ N°{cg['numero1']} {cg['cheval1']} + N°{cg['numero2']} {cg['cheval2']}")
    print(f"     Mise : {cg['mise_suggeree']}€ | Confiance : {cg['confiance']}")
    print(f"     {cg['justification']}")

    cp = recommendations['couple_place']
    print(f"\n  🔗 COUPLÉ PLACÉ")
    print(f"     ➤ N°{cp['numero1']} {cp['cheval1']} + N°{cp['numero2']} {cp['cheval2']}")
    print(f"     Mise : {cp['mise_suggeree']}€ | Confiance : {cp['confiance']}")

    print(f"\n  💼 Budget total suggéré : {recommendations['budget_total']}€")
    print(f"{'='*65}\n")


def save_json(data, date):
    path = f"{os.environ.get('TURF_DIR', '/home/h3r7/turf_scraper')}/scoring_{date.replace('-','')}.json"
    with open(path, 'w', encoding='utf-8') as f:
        json.dump(data, f, indent=2, ensure_ascii=False)
    return path


def format_telegram(recommendations, race_info):
    sg = recommendations['simple_gagnant']
    sp = recommendations['simple_place']
    cg = recommendations['couple_gagnant']
    cp = recommendations['couple_place']
    top3 = recommendations['top3_scores']

    msg = f"""🏇 *QUINTÉ+ — {race_info.get('hippodrome','?')} {race_info.get('heure','?')}*
_{race_info.get('nom','')}_

📊 *TOP 3 SCORING*
"""
    for h in top3[:3]:
        msg += f"  {h['rang']}. N°{h['numero']} *{h['nom']}* — score {h['score']} | cote {h['cote']} | forme {h['forme']}\n"

    msg += f"""
💰 *RECOMMANDATIONS*

🎯 *Simple Gagnant* : N°{sg['numero']} {sg['cheval']} @ {sg['cote']}/1
   Mise {sg['mise_suggeree']}€ → gain potentiel {sg['gain_potentiel']}€
   {sg['confiance']} | {sg['justification']}

🛡️ *Simple Placé* : N°{sp['numero']} {sp['cheval']}
   Mise {sp['mise_suggeree']}€ | {sp['confiance']}

🔗 *Couplé Gagnant* : {cg['numero1']}-{cg['numero2']} ({cg['cheval1']} / {cg['cheval2']})
   Mise {cg['mise_suggeree']}€ | {cg['confiance']}

🔗 *Couplé Placé* : {cp['numero1']}-{cp['numero2']} ({cp['cheval1']} / {cp['cheval2']})
   Mise {cp['mise_suggeree']}€ | {cp['confiance']}

💼 Budget total : {recommendations['budget_total']}€
"""
    return msg


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

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

    print(f"\n{'='*65}")
    print(f"🧠 SCORING ENGINE — {datetime.now().strftime('%d/%m/%Y %H:%M')}")
    print(f"{'='*65}\n")

    init_scoring_table()

    # Récupérer le programme
    print("📡 Récupération du programme PMU...")
    try:
        url = f"https://turfinfo.api.pmu.fr/rest/client/1/programme/{date_pmu}/reunions"
        r = requests.get(url, headers=HEADERS, timeout=15)
        reunions = r.json().get('programme', {}).get('reunions', [])
        print(f"   ✅ {len(reunions)} réunion(s)")
    except Exception as e:
        print(f"   ❌ {e}")
        return

    # Trouver le Quinté+
    quinte = 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:
                quinte = (reunion['numOfficiel'], course['numOrdre'],
                          libelle, reunion['hippodrome']['libelleCourt'],
                          course.get('heureDepart', 0))
                break
        if quinte:
            break

    if not quinte:
        print("❌ Quinté+ non trouvé")
        return

    num_r, num_c, libelle, hippodrome, heure_ts = quinte
    heure = datetime.fromtimestamp(heure_ts/1000).strftime('%H:%M') if heure_ts else '13:55'
    race_info = {'nom': libelle, 'hippodrome': hippodrome, 'heure': heure}
    print(f"   🏇 {libelle} — {hippodrome} {heure}")

    # Récupérer les participants
    print(f"\n📡 Récupération des participants R{num_r}C{num_c}...")
    try:
        url = f"https://turfinfo.api.pmu.fr/rest/client/1/programme/{date_pmu}/R{num_r}/C{num_c}/participants"
        r = requests.get(url, headers=HEADERS, timeout=15)
        participants = [p for p in r.json().get('participants', []) if p.get('statut') == 'PARTANT']
        print(f"   ✅ {len(participants)} partants")
    except Exception as e:
        print(f"   ❌ {e}")
        return

    # Calculer le scoring
    print(f"\n🧠 Calcul du scoring composite...")
    scored_horses = []
    for p in participants:
        score, details = score_cheval(p, participants)
        scored_horses.append({
            'nom':     p['nom'],
            'numero':  p['numPmu'],
            'score':   score,
            'details': details,
        })

    # Construire les recommandations
    recommendations = build_recommendations(scored_horses)

    # Afficher le rapport
    print_report(scored_horses, recommendations, race_info)

    # Sauvegarder en BDD
    save_scoring(today, libelle, scored_horses, recommendations)
    print(f"💾 Scoring sauvegardé en BDD")

    # Sauvegarder en JSON
    output = {
        'date': today,
        'race': race_info,
        'scored_horses': sorted(scored_horses, key=lambda x: x['score'], reverse=True),
        'recommendations': recommendations,
    }
    json_path = save_json(output, today)
    print(f"📁 JSON : {json_path}")

    # Message Telegram
    telegram_msg = format_telegram(recommendations, race_info)
    telegram_path = f"{os.environ.get('TURF_DIR', '/home/h3r7/turf_scraper')}/telegram_scoring_{today.replace('-','')}.txt"
    with open(telegram_path, 'w', encoding='utf-8') as f:
        f.write(telegram_msg)
    print(f"📱 Message Telegram : {telegram_path}")
    print(f"\n{'─'*65}")
    print(telegram_msg)

if __name__ == "__main__":
    main()
