#!/usr/bin/env python3
"""
Predictions routes for API v1.

GET /api/v1/predictions/top3   — Top 3 global du jour (free tier, 1/day limit)
GET /api/v1/predictions/all    — Toutes prédictions (premium+)
"""

from datetime import datetime, timedelta
from flask import Blueprint, jsonify, request

from api_v1.utils import (
    get_db,
    table_exists,
    internal_error,
    not_found,
    get_pagination_params,
    paginate_query,
)
from auth import jwt_required_middleware, plan_required, free_daily_limit_check

predictions_bp = Blueprint("v1_predictions", __name__, url_prefix="/api/v1/predictions")


def _fetch_ml_predictions(
    conn, date: str, limit: int = None, offset: int = 0, include_weather: bool = False
):
    """Shared helper — returns rows from ml_predictions_cache.

    include_weather=True adds terrain_condition and weather_impact columns
    via LEFT JOIN on pmu_meteo (premium routes only).
    """
    if not table_exists(conn, "ml_predictions_cache"):
        return [], 0

    count_row = conn.execute(
        "SELECT COUNT(*) as cnt FROM ml_predictions_cache WHERE date = ?",
        (date,),
    ).fetchone()
    total = count_row["cnt"] if count_row else 0

    if (
        include_weather
        and table_exists(conn, "pmu_meteo")
        and table_exists(conn, "pmu_courses")
    ):
        sql = """SELECT
                     m.race_label, m.hippodrome, m.discipline, m.distance, m.heure,
                     m.horse_name, m.horse_number, m.odds, m.prob_top1, m.prob_top3,
                     m.ml_score, m.recommendation, m.is_value_bet, m.risque_label, m.risque_score,
                     c.penetrometre_intitule,
                     mt.nebulositecode, mt.nebulosite_court, mt.temperature, mt.force_vent
                 FROM ml_predictions_cache m
                 LEFT JOIN pmu_courses c
                     ON c.date_programme = m.date
                     AND c.num_reunion = m.num_reunion
                     AND c.num_course = m.num_course
                 LEFT JOIN pmu_meteo mt
                     ON mt.date_programme = m.date
                     AND mt.num_reunion = m.num_reunion
                 WHERE m.date = ?
                 ORDER BY m.ml_score DESC"""
    else:
        sql = """SELECT
                     race_label, hippodrome, discipline, distance, heure,
                     horse_name, horse_number, odds, prob_top1, prob_top3,
                     ml_score, recommendation, is_value_bet, risque_label, risque_score
                 FROM ml_predictions_cache
                 WHERE date = ?
                 ORDER BY ml_score DESC"""
    params = [date]

    if limit is not None:
        sql += " LIMIT ? OFFSET ?"
        params += [limit, offset]

    rows = conn.execute(sql, params).fetchall()

    results = []
    for r in rows:
        row_dict = dict(r)
        if include_weather:
            # Compute derived fields from raw columns
            penetrometre = row_dict.pop("penetrometre_intitule", None) or ""
            # Import inline to avoid circular dependency at module level
            from scoring_v2 import get_terrain_condition, compute_weather_impact

            terrain_condition = (
                get_terrain_condition(penetrometre) if penetrometre else "inconnu"
            )
            weather_data = None
            if (
                row_dict.get("nebulositecode") is not None
                or row_dict.get("temperature") is not None
            ):
                weather_data = {
                    "nebulositecode": row_dict.pop("nebulositecode", None),
                    "nebulosite_court": row_dict.pop("nebulosite_court", None),
                    "temperature": row_dict.pop("temperature", None),
                    "force_vent": row_dict.pop("force_vent", None),
                }
            else:
                # Remove raw meteo columns even if NULL
                row_dict.pop("nebulositecode", None)
                row_dict.pop("nebulosite_court", None)
                row_dict.pop("temperature", None)
                row_dict.pop("force_vent", None)
            weather_impact = compute_weather_impact(weather_data, terrain_condition)
            row_dict["terrain_condition"] = terrain_condition
            row_dict["weather_impact"] = weather_impact
        results.append(row_dict)

    return results, total


# ──────────────────────────────────────────────────────────────
# GET /api/v1/predictions/top3
# ──────────────────────────────────────────────────────────────


@predictions_bp.route("/top3", methods=["GET"])
@jwt_required_middleware
@free_daily_limit_check
def predictions_top3():
    """
    Top 3 prédictions du jour
    ---
    tags:
      - Prédictions
    summary: Top 3 chevaux avec le meilleur score ML du jour (free tier inclus)
    security:
      - Bearer: []
    parameters:
      - name: date
        in: query
        type: string
        format: date
        description: Date au format YYYY-MM-DD (défaut aujourd'hui)
    responses:
      200:
        description: Top 3 prédictions ML du jour
      401:
        description: Token invalide
      429:
        description: Limite quotidienne free tier atteinte
    """
    date_param = request.args.get("date", datetime.now().strftime("%Y-%m-%d"))

    conn = get_db()
    try:
        predictions, _ = _fetch_ml_predictions(conn, date_param, limit=3, offset=0)

        return jsonify(
            {
                "status": "ok",
                "date": date_param,
                "top3": predictions,
            }
        ), 200
    except Exception as e:
        return internal_error(str(e))
    finally:
        conn.close()


# ──────────────────────────────────────────────────────────────
# GET /api/v1/predictions/all
# ──────────────────────────────────────────────────────────────


@predictions_bp.route("/all", methods=["GET"])
@jwt_required_middleware
@plan_required("premium", "pro")
def predictions_all():
    """
    Toutes les prédictions du jour
    ---
    tags:
      - Prédictions
    summary: Toutes les prédictions ML du jour — accès premium et pro uniquement
    security:
      - Bearer: []
    parameters:
      - name: date
        in: query
        type: string
        format: date
        description: Date au format YYYY-MM-DD (défaut aujourd'hui)
      - name: limit
        in: query
        type: integer
        default: 20
      - name: offset
        in: query
        type: integer
        default: 0
    responses:
      200:
        description: Toutes les prédictions ML
      401:
        description: Token invalide
      403:
        description: Plan insuffisant (premium ou pro requis)
    """
    date_param = request.args.get("date", datetime.now().strftime("%Y-%m-%d"))
    limit, offset = get_pagination_params(default_limit=50, max_limit=500)

    conn = get_db()
    try:
        predictions, total = _fetch_ml_predictions(
            conn, date_param, limit=limit, offset=offset, include_weather=True
        )
        pagination = paginate_query(predictions, total, limit, offset)

        return jsonify(
            {
                "status": "ok",
                "date": date_param,
                "predictions": predictions,
                **pagination,
            }
        ), 200
    except Exception as e:
        return internal_error(str(e))
    finally:
        conn.close()
