"""Flask integration for dogpile.cache.

This module provides Flask-specific integration for the caching system,
including app initialization, request hooks, and login handlers.
"""

from flask import Flask, g, current_app
from loguru import logger
from dogpile.cache.api import NO_VALUE

from .config import (
    SingleTierCache,
    TwoTierCache,  # Alias for compatibility
)


def init_cache(app: Flask) -> None:
    """Initialize caching for Flask application.

    Args:
        app: Flask application instance
    """
    # Get cache configuration from app config or environment
    enable_cache = app.config.get("ENABLE_CACHE", True)

    if not enable_cache:
        logger.warning("Cache is disabled via configuration")
        app.cache = None
        return

    # Create single-tier cache at app level
    try:
        # Create single-tier cache with 1 hour TTL
        app.cache = SingleTierCache(enable_metrics=True)

        logger.info("Cache initialized successfully")

    except Exception:
        logger.exception("Failed to initialize cache")
        # Fall back to null cache
        app.cache = None

    # No cache invalidation or warming needed
    # Settings and API keys are accessed directly without caching
    logger.info("Cache configured - no warming or invalidation needed")

    # Register request handlers
    _register_request_handlers(app)


def _register_request_handlers(app: Flask) -> None:
    """Register request-level cache handlers.

    Args:
        app: Flask application
    """

    @app.before_request
    def before_request():
        """Make cache available in g."""
        g.cache = current_app.cache

    @app.teardown_request
    def teardown_request(exception=None):
        """Clean up request-level cache data."""
        # Clear any request-specific cache data
        if hasattr(g, "cache_metrics"):
            # Log cache metrics for this request
            metrics = g.cache_metrics
            if metrics and metrics.get("total_requests", 0) > 0:
                logger.debug(
                    f"Request cache stats: "
                    f"hits={metrics.get('total_hits', 0)} "
                    f"hit_rate={metrics.get('hit_rate', 0):.2%}"
                )


def get_cache() -> TwoTierCache:
    """Get cache instance from Flask context.

    Returns:
        TwoTierCache instance or None
    """
    if hasattr(g, "cache"):
        return g.cache
    elif hasattr(current_app, "cache"):
        return current_app.cache
    else:
        logger.warning("No cache available in Flask context")
        return None


def cache_metrics_middleware(app: Flask) -> None:
    """Add cache metrics collection middleware.

    Args:
        app: Flask application
    """

    @app.before_request
    def collect_cache_metrics():
        """Start collecting cache metrics for request."""
        cache = get_cache()
        if cache:
            g.cache_metrics_start = cache.get_metrics()

    @app.after_request
    def log_cache_metrics(response):
        """Log cache metrics for request."""
        cache = get_cache()
        if cache and hasattr(g, "cache_metrics_start"):
            end_metrics = cache.get_metrics()

            # Calculate delta
            request_hits = (
                end_metrics["total_hits"] - g.cache_metrics_start["total_hits"]
            )
            request_total = (
                end_metrics["total_requests"]
                - g.cache_metrics_start["total_requests"]
            )

            if request_total > 0:
                request_hit_rate = request_hits / request_total
                # Add custom header for monitoring
                response.headers["X-Cache-Hit-Rate"] = f"{request_hit_rate:.2%}"

        return response


# Convenience decorators for views
def cached_view(namespace: str, expiration_time: int = 3600):
    """Decorator to cache view results.

    Args:
        namespace: Cache namespace
        expiration_time: TTL in seconds
    """

    def decorator(func):
        def wrapper(*args, **kwargs):
            cache = get_cache()
            if not cache:
                return func(*args, **kwargs)

            # Generate cache key from view and args
            from flask import request

            user_id = str(g.user.id) if hasattr(g, "user") else "anonymous"
            key = f"{func.__name__}:{request.path}:{request.query_string.decode()}"

            # Try cache
            value = cache.get(user_id, namespace, key)
            if value is not None and value != NO_VALUE:
                return value

            # Compute value
            value = func(*args, **kwargs)

            # Cache it
            cache.set(user_id, namespace, key, value, expiration_time)

            return value

        return wrapper

    return decorator
