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

GET /api/v1/history  — Historique des prédictions avec filtre date range,
                       limité selon le plan (Free: 7j, Premium: 90j, Pro: illimité)

Ticket: HRT-81 — Historique limité/illimité selon plan (Free/Premium/Pro)
"""

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

from api_v1.utils import (
    get_db,
    table_exists,
    internal_error,
    bad_request,
    forbidden,
    get_pagination_params,
    paginate_query,
)
# Auth: try flask_jwt_extended (app_v1) first, fall back to saas_auth (portal_server)
try:
    from auth import jwt_required_middleware
except ImportError:
    from saas_auth import require_auth as jwt_required_middleware

history_bp = Blueprint("v1_history", __name__, url_prefix="/api/v1/history")

# ──────────────────────────────────────────────────────────────
# Plan limits (days of history accessible; None = unlimited)
# ──────────────────────────────────────────────────────────────

HISTORY_DAYS = {
    "free": 7,
    "premium": 90,
    "pro": None,  # illimité
}

# Fallback for unknown plans: treat like free
_DEFAULT_LIMIT = 7


def _get_plan_max_days(plan: str):
    """Return the max history days allowed for the given plan, or default."""
    return HISTORY_DAYS.get(plan, _DEFAULT_LIMIT)


def _parse_date(date_str: str, param_name: str):
    """Parse YYYY-MM-DD date string, raise ValueError with context on failure."""
    try:
        return datetime.strptime(date_str, "%Y-%m-%d").date()
    except ValueError:
        raise ValueError(
            f"Paramètre '{param_name}' invalide : format attendu YYYY-MM-DD, reçu '{date_str}'"
        )


# ──────────────────────────────────────────────────────────────
# GET /api/v1/history
# ──────────────────────────────────────────────────────────────


@history_bp.route("", methods=["GET"])
@jwt_required_middleware
def get_history():
    """
    Historique des prédictions ML avec filtre date range
    ---
    tags:
      - Historique
    summary: |
      Historique des prédictions sur une plage de dates.
      Limite selon le plan :
        - Free    : 7 derniers jours
        - Premium : 90 derniers jours
        - Pro     : illimité
    security:
      - Bearer: []
    parameters:
      - name: start
        in: query
        type: string
        format: date
        description: Date de début au format YYYY-MM-DD (défaut : aujourd'hui - max_days du plan)
      - name: end
        in: query
        type: string
        format: date
        description: Date de fin au format YYYY-MM-DD (défaut : aujourd'hui)
      - name: limit
        in: query
        type: integer
        default: 50
        description: Nombre de résultats par page (max 500)
      - name: offset
        in: query
        type: integer
        default: 0
    responses:
      200:
        description: Historique des prédictions ML
      400:
        description: Paramètre de date invalide
      401:
        description: Token invalide ou manquant
      403:
        description: Plage de dates hors limite du plan — upgrade requis
    """
    user = getattr(request, "current_user", None) or getattr(g, "current_user", None)
    if not user:
        return jsonify({"error": "Non authentifié"}), 401

    plan = user.get("plan", "free")
    today = datetime.now().date()
    max_days = _get_plan_max_days(plan)

    # ── Parse end date ────────────────────────────────────────
    end_str = request.args.get("end", today.isoformat())
    try:
        end_date = _parse_date(end_str, "end")
    except ValueError as exc:
        return bad_request(str(exc))

    # ── Parse start date ─────────────────────────────────────
    if max_days is not None:
        default_start = today - timedelta(days=max_days - 1)
    else:
        # Pro: default to 30 days back when no start provided
        default_start = today - timedelta(days=29)

    start_str = request.args.get("start", default_start.isoformat())
    try:
        start_date = _parse_date(start_str, "start")
    except ValueError as exc:
        return bad_request(str(exc))

    # ── Validate ordering ─────────────────────────────────────
    if start_date > end_date:
        return bad_request(
            f"'start' ({start_str}) ne peut pas être postérieur à 'end' ({end_str})"
        )

    # ── Enforce plan window ───────────────────────────────────
    if max_days is not None:
        earliest_allowed = today - timedelta(days=max_days - 1)
        if start_date < earliest_allowed:
            return forbidden(
                message=(
                    f"Historique limité à {max_days} jours pour le plan '{plan}'. "
                    f"Date de début minimale autorisée : {earliest_allowed.isoformat()}. "
                    f"Passez à un plan supérieur pour accéder à un historique plus long."
                ),
                required_plans=["premium", "pro"] if plan == "free" else ["pro"],
                current_plan=plan,
            )

    # ── Pagination ────────────────────────────────────────────
    limit, offset = get_pagination_params(default_limit=50, max_limit=500)

    # ── Query ─────────────────────────────────────────────────
    conn = get_db()
    try:
        if not table_exists(conn, "ml_predictions_cache"):
            return jsonify(
                {
                    "status": "ok",
                    "plan": plan,
                    "start": start_date.isoformat(),
                    "end": end_date.isoformat(),
                    "history": [],
                    **paginate_query([], 0, limit, offset),
                }
            ), 200

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

        sql = """
            SELECT
                id, date, horse_name, prob_top1, prob_top3,
                ml_score, race_label, hippodrome, heure, is_value_bet
            FROM ml_predictions_cache
            WHERE date >= ? AND date <= ?
            ORDER BY date DESC, ml_score DESC
            LIMIT ? OFFSET ?
        """
        rows = conn.execute(
            sql,
            (start_date.isoformat(), end_date.isoformat(), limit, offset),
        ).fetchall()

        history = [dict(r) for r in rows]

        return jsonify(
            {
                "status": "ok",
                "plan": plan,
                "history_limit_days": max_days,
                "start": start_date.isoformat(),
                "end": end_date.isoformat(),
                "history": history,
                **paginate_query(history, total, limit, offset),
            }
        ), 200

    except Exception as exc:
        return internal_error(str(exc))
    finally:
        conn.close()
