from fastapi import FastAPI
from pydantic import BaseModel
import asyncio
import pickle
from typing import List, Dict
import numpy as np

app = FastAPI()

# Charger le modèle
with open('pipeline_xgb.pkl', 'rb') as file:
    model = pickle.load(file)

# Définir les modèles de requête et de réponse
class TennisMatch(BaseModel):
    match_id: int
    player_id1: int
    player_id2: int
    p1_niveau_rank: float
    p1_niveau_win_total: float
    p1_niveau_win_surface_total: float
    p1_h2h_win_total: float
    p1_h2h_win_1an: float
    p1_h2h_win_surface_total: float
    p1_h2h_win_sets: float
    p1_progression_win_1an: float
    p1_progression_win_surface_1an: float
    p1_progression_win_last_50matchs: float
    p1_progression_win_last_10matchs: float
    p1_forme_matchs_30j: float
    p1_forme_matchs_length_tournament: float
    p1_tendance_loose_favori_30j: float
    p1_tendance_win_outsider_30j: float
    p1_confiance_first_service_last_match: float
    p1_confiance_points_first_service_last_match: float
    p1_confiance_break_saved_last_match: float
    p2_niveau_rank: float
    p2_niveau_win_total: float
    p2_niveau_win_surface_total: float
    p2_h2h_win_total: float
    p2_h2h_win_1an: float
    p2_h2h_win_surface_total: float
    p2_h2h_win_sets: float
    p2_progression_win_1an: float
    p2_progression_win_surface_1an: float
    p2_progression_win_last_50matchs: float
    p2_progression_win_last_10matchs: float
    p2_forme_matchs_30j: float
    p2_forme_matchs_length_tournament: float
    p2_tendance_loose_favori_30j: float
    p2_tendance_win_outsider_30j: float
    p2_confiance_first_service_last_match: float
    p2_confiance_points_first_service_last_match: float
    p2_confiance_break_saved_last_match: float
    idc_p1_motivation_enjeu: float
    idc_p1_motivation_revanche: float
    idc_p1_motivation_surface: float
    idc_p1_tactique_profil: float
    idc_p1_tactique_service1: float
    idc_p1_tactique_service2: float
    idc_p1_tactique_retourservice1: float
    idc_p1_tactique_retourservice2: float
    idc_p1_tactique_breaksauve: float
    idc_p1_tactique_breakgagne: float
    idc_p1_tactique_tiebreak: float
    idc_p1_historique_match: float
    idc_p1_historique_book: float
    idc_p1_historique_estimated: float
    idc_p2_motivation_enjeu: float
    idc_p2_motivation_revanche: float
    idc_p2_motivation_surface: float
    idc_p2_tactique_profil: float
    idc_p2_tactique_service1: float
    idc_p2_tactique_service2: float
    idc_p2_tactique_retourservice1: float
    idc_p2_tactique_retourservice2: float
    idc_p2_tactique_breaksauve: float
    idc_p2_tactique_breakgagne: float
    idc_p2_tactique_tiebreak: float
    idc_p2_historique_match: float
    idc_p2_historique_book: float
    idc_p2_historique_estimated: float
    tournament_round: float
    tournament_type: float
    tournament_surface: float

class MatchPrediction(BaseModel):
    match_id: int
    win_probability_j1: float
    win_probability_j2: float

class BatchPredictionRequest(BaseModel):
    matches: List[TennisMatch]

class BatchPredictionResponse(BaseModel):
    predictions: List[MatchPrediction]

# Définir la fonction de prédiction
async def predict_match(features: Dict[str, float]):
    match_id = int(features.pop('match_id'))  # Extraire l'identifiant du match
    prediction = await asyncio.to_thread(model.predict_proba, [features])
    return MatchPrediction(
        match_id=match_id,
        win_probability_j1=prediction[0][0],
        win_probability_j2=prediction[0][1]
    )

# Définir le point de terminaison pour la prédiction en lot
@app.post("/predict_batch", response_model=BatchPredictionResponse)
async def predict_batch(request: BatchPredictionRequest):

    prediction_tasks = [
        predict_match(match.dict())
        for match in request.matches
    ]
    
    predictions = await asyncio.gather(*prediction_tasks)

    return BatchPredictionResponse(predictions=predictions)

# Définir le point de terminaison pour une seule prédiction
@app.post("/predict", response_model=MatchPrediction)
async def predict_match(features: Dict[str, float]):
    match_id = int(features['match_id'])  # Extraire l'identifiant du match
    # Assurez-vous que les caractéristiques sont dans le bon format pour le modèle
    feature_list = [features[key] for key in sorted(features.keys())]
    feature_array = np.array(feature_list).reshape(1, -1)  # Transformer en tableau 2D avec une seule ligne
    prediction = await asyncio.to_thread(model.predict_proba, feature_array)
    return MatchPrediction(
        match_id=match_id,
        win_probability_j1=prediction[0][0],
        win_probability_j2=prediction[0][1]
    )
