#!/usr/bin/env python3
"""
Prometheus metrics instrumentation for Turf SaaS.
Import this module in Flask apps to expose /metrics endpoint.
"""

import time
import functools
import logging
from typing import Callable, Any

try:
    from prometheus_client import (
        Counter,
        Histogram,
        Gauge,
        Summary,
        generate_latest,
        CONTENT_TYPE_LATEST,
        CollectorRegistry,
        multiprocess,
        REGISTRY,
    )

    PROMETHEUS_AVAILABLE = True
except ImportError:
    PROMETHEUS_AVAILABLE = False

logger = logging.getLogger(__name__)

# ============================================================
# Metric definitions
# ============================================================

if PROMETHEUS_AVAILABLE:
    # HTTP metrics
    HTTP_REQUESTS_TOTAL = Counter(
        "http_requests_total",
        "Total number of HTTP requests",
        ["method", "endpoint", "status_code", "service"],
    )

    HTTP_REQUEST_DURATION = Histogram(
        "http_request_duration_seconds",
        "HTTP request duration in seconds",
        ["method", "endpoint", "service"],
        buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0],
    )

    HTTP_REQUESTS_IN_PROGRESS = Gauge(
        "http_requests_in_progress",
        "Number of HTTP requests currently being processed",
        ["method", "endpoint", "service"],
    )

    # ML prediction metrics
    ML_PREDICTIONS_TOTAL = Counter(
        "ml_predictions_total",
        "Total ML prediction requests",
        ["model_type", "race_type"],
    )

    ML_PREDICTION_DURATION = Histogram(
        "ml_prediction_duration_seconds",
        "ML prediction duration in seconds",
        ["model_type"],
        buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0],
    )

    ML_PREDICTION_ACCURACY = Gauge(
        "ml_prediction_accuracy_ratio",
        "Rolling ML prediction accuracy (top-1, top-3)",
        ["accuracy_type"],
    )

    ML_PREDICTION_DRIFT = Gauge(
        "ml_prediction_drift_score",
        "Feature drift score for ML models (0=no drift, 1=full drift)",
        ["feature_group"],
    )

    # Database metrics
    DB_QUERIES_TOTAL = Counter(
        "db_queries_total", "Total database queries", ["operation", "table"]
    )

    DB_QUERY_DURATION = Histogram(
        "db_query_duration_seconds",
        "Database query duration",
        ["operation"],
        buckets=[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0],
    )

    DB_CONNECTION_POOL_SIZE = Gauge(
        "db_connection_pool_size", "Current database connection pool size"
    )

    # Business metrics
    RACES_SCRAPED_TOTAL = Counter(
        "races_scraped_total", "Total number of races scraped", ["source", "discipline"]
    )

    PREDICTIONS_ACCURACY_DAILY = Gauge(
        "predictions_accuracy_daily_ratio",
        "Daily prediction accuracy ratio",
        ["date", "race_type"],
    )

    ACTIVE_SUBSCRIPTIONS = Gauge(
        "active_subscriptions_total", "Number of active SaaS subscriptions", ["plan"]
    )

    # App health
    APP_INFO = Gauge(
        "app_info", "Application build information", ["version", "service", "env"]
    )


# ============================================================
# Flask integration
# ============================================================


def init_metrics(app, service_name: str = "unknown"):
    """
    Register Prometheus metrics middleware on a Flask app.

    Usage:
        from metrics import init_metrics
        init_metrics(app, service_name="combined-api")
    """
    if not PROMETHEUS_AVAILABLE:
        logger.warning("prometheus_client not installed — metrics disabled")
        return

    from flask import request, Response

    # Set app info gauge
    APP_INFO.labels(
        version=app.config.get("VERSION", "unknown"),
        service=service_name,
        env=app.config.get("ENV", "unknown"),
    ).set(1)

    @app.before_request
    def before_request():
        request._start_time = time.time()
        HTTP_REQUESTS_IN_PROGRESS.labels(
            method=request.method, endpoint=request.path, service=service_name
        ).inc()

    @app.after_request
    def after_request(response):
        duration = time.time() - getattr(request, "_start_time", time.time())
        endpoint = request.path

        HTTP_REQUESTS_TOTAL.labels(
            method=request.method,
            endpoint=endpoint,
            status_code=str(response.status_code),
            service=service_name,
        ).inc()

        HTTP_REQUEST_DURATION.labels(
            method=request.method, endpoint=endpoint, service=service_name
        ).observe(duration)

        HTTP_REQUESTS_IN_PROGRESS.labels(
            method=request.method, endpoint=endpoint, service=service_name
        ).dec()

        return response

    @app.route("/metrics")
    def metrics_endpoint():
        """Prometheus metrics scrape endpoint."""
        return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)

    @app.route("/health")
    def health_endpoint():
        """Docker / load-balancer health check endpoint."""
        from flask import jsonify

        return jsonify({"status": "ok", "service": service_name})

    logger.info(f"Prometheus metrics initialized for service: {service_name}")


# ============================================================
# Decorator helpers
# ============================================================


def track_ml_prediction(model_type: str = "xgboost", race_type: str = "flat"):
    """Decorator to track ML prediction calls."""

    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if not PROMETHEUS_AVAILABLE:
                return func(*args, **kwargs)
            start = time.time()
            try:
                result = func(*args, **kwargs)
                ML_PREDICTIONS_TOTAL.labels(
                    model_type=model_type, race_type=race_type
                ).inc()
                return result
            finally:
                ML_PREDICTION_DURATION.labels(model_type=model_type).observe(
                    time.time() - start
                )

        return wrapper

    return decorator


def track_db_query(operation: str = "select", table: str = "unknown"):
    """Decorator to track DB query calls."""

    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if not PROMETHEUS_AVAILABLE:
                return func(*args, **kwargs)
            start = time.time()
            try:
                result = func(*args, **kwargs)
                DB_QUERIES_TOTAL.labels(operation=operation, table=table).inc()
                return result
            finally:
                DB_QUERY_DURATION.labels(operation=operation).observe(
                    time.time() - start
                )

        return wrapper

    return decorator


def update_ml_accuracy(top1_accuracy: float, top3_accuracy: float):
    """Update ML accuracy gauges (call from scheduler)."""
    if not PROMETHEUS_AVAILABLE:
        return
    ML_PREDICTION_ACCURACY.labels(accuracy_type="top1").set(top1_accuracy)
    ML_PREDICTION_ACCURACY.labels(accuracy_type="top3").set(top3_accuracy)


def update_subscription_count(plan_counts: dict):
    """Update subscription count gauges."""
    if not PROMETHEUS_AVAILABLE:
        return
    for plan, count in plan_counts.items():
        ACTIVE_SUBSCRIPTIONS.labels(plan=plan).set(count)
