"""
Performance Dashboard View for monitoring application performance.

This view provides a dashboard for administrators to monitor:
- Cache statistics (hit rate, memory usage)
- Database query performance
- Response times
- Error rates
- Connection pool status

Access: Staff/Admin only
URL: /admin/performance/ (configured in urls.py)
"""

import logging
import time
from typing import Any

from django.conf import settings
from django.contrib.admin.views.decorators import staff_member_required
from django.core.cache import caches
from django.db import connection
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic import TemplateView

from apps.core.services.enhanced_cache_service import CacheMonitor

logger = logging.getLogger(__name__)


@method_decorator(staff_member_required, name="dispatch")
class PerformanceDashboardView(TemplateView):
    """
    Performance dashboard for monitoring application metrics.

    Accessible only to staff members.
    """

    template_name = "core/performance_dashboard.html"

    def get_context_data(self, **kwargs) -> dict[str, Any]:
        context = super().get_context_data(**kwargs)

        # Get cache statistics
        context["cache_stats"] = self._get_cache_stats()

        # Get database stats
        context["database_stats"] = self._get_database_stats()

        # Get middleware settings
        context["middleware_config"] = self._get_middleware_config()

        # Get cache configuration
        context["cache_config"] = self._get_cache_config()

        return context

    def _get_cache_stats(self) -> dict[str, Any]:
        """Get cache statistics from all configured caches."""
        stats = {}

        try:
            cache_monitor = CacheMonitor()
            stats["default"] = cache_monitor.get_cache_stats()
        except Exception as e:
            stats["default"] = {"error": str(e)}

        # Try to get stats for each configured cache
        for cache_name in settings.CACHES:
            try:
                cache = caches[cache_name]
                cache_backend = cache.__class__.__name__

                cache_stats = {
                    "backend": cache_backend,
                    "key_prefix": getattr(cache, "key_prefix", "N/A"),
                }

                # Try to get Redis-specific stats
                if "Redis" in cache_backend:
                    try:
                        client = cache._cache.get_client()
                        info = client.info()
                        cache_stats.update(
                            {
                                "connected_clients": info.get("connected_clients"),
                                "used_memory_human": info.get("used_memory_human"),
                                "keyspace_hits": info.get("keyspace_hits", 0),
                                "keyspace_misses": info.get("keyspace_misses", 0),
                                "total_commands": info.get("total_commands_processed"),
                            }
                        )

                        # Calculate hit rate
                        hits = info.get("keyspace_hits", 0)
                        misses = info.get("keyspace_misses", 0)
                        if hits + misses > 0:
                            cache_stats["hit_rate"] = f"{(hits / (hits + misses) * 100):.1f}%"
                        else:
                            cache_stats["hit_rate"] = "N/A"
                    except Exception:
                        pass

                stats[cache_name] = cache_stats

            except Exception as e:
                stats[cache_name] = {"error": str(e)}

        return stats

    def _get_database_stats(self) -> dict[str, Any]:
        """Get database connection and query statistics."""
        stats = {}

        try:
            # Get database connection info
            db_settings = settings.DATABASES.get("default", {})
            stats["engine"] = db_settings.get("ENGINE", "Unknown").split(".")[-1]
            stats["name"] = db_settings.get("NAME", "Unknown")
            stats["conn_max_age"] = getattr(settings, "CONN_MAX_AGE", 0)

            # Test connection and get server version
            with connection.cursor() as cursor:
                cursor.execute("SELECT version();")
                stats["server_version"] = cursor.fetchone()[0]

                # Get connection count (PostgreSQL specific)
                try:
                    cursor.execute(
                        "SELECT count(*) FROM pg_stat_activity WHERE datname = %s;", [db_settings.get("NAME")]
                    )
                    stats["active_connections"] = cursor.fetchone()[0]
                except Exception:
                    stats["active_connections"] = "N/A"

        except Exception as e:
            stats["error"] = str(e)

        return stats

    def _get_middleware_config(self) -> dict[str, Any]:
        """Get middleware configuration summary."""
        middleware = settings.MIDDLEWARE
        return {
            "count": len(middleware),
            "has_gzip": "django.middleware.gzip.GZipMiddleware" in middleware,
            "has_cache_update": "django.middleware.cache.UpdateCacheMiddleware" in middleware,
            "has_cache_fetch": "django.middleware.cache.FetchFromCacheMiddleware" in middleware,
            "has_performance": any("performance" in m.lower() for m in middleware),
            "middleware_list": middleware,
        }

    def _get_cache_config(self) -> dict[str, Any]:
        """Get cache configuration summary."""
        cache_config = {}

        for cache_name, config in settings.CACHES.items():
            cache_config[cache_name] = {
                "backend": config.get("BACKEND", "Unknown").split(".")[-1],
                "location": config.get("LOCATION", "Unknown"),
                "key_prefix": config.get("KEY_PREFIX", "None"),
                "version": config.get("VERSION", 1),
            }

            # Get connection pool settings if available
            options = config.get("OPTIONS", {})
            pool_kwargs = options.get("CONNECTION_POOL_CLASS_KWARGS", {})
            if pool_kwargs:
                cache_config[cache_name]["max_connections"] = pool_kwargs.get("max_connections", "N/A")
                cache_config[cache_name]["timeout"] = pool_kwargs.get("timeout", "N/A")

        return cache_config


@method_decorator(staff_member_required, name="dispatch")
class PerformanceMetricsAPIView(View):
    """
    JSON API endpoint for real-time performance metrics.

    Used by the dashboard for AJAX updates.
    """

    def get(self, request) -> JsonResponse:
        metrics = {}

        # Cache stats
        try:
            cache_monitor = CacheMonitor()
            metrics["cache"] = cache_monitor.get_cache_stats()
        except Exception as e:
            metrics["cache"] = {"error": str(e)}

        # Quick database check
        try:
            start_time = time.time()
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1")
                cursor.fetchone()
            metrics["database"] = {
                "status": "healthy",
                "response_time_ms": round((time.time() - start_time) * 1000, 2),
            }
        except Exception as e:
            metrics["database"] = {
                "status": "error",
                "error": str(e),
            }

        # Quick cache check
        try:
            cache = caches["default"]
            test_key = "_performance_check"
            cache.set(test_key, 1, 10)
            if cache.get(test_key) == 1:
                metrics["cache_health"] = "healthy"
            else:
                metrics["cache_health"] = "degraded"
            cache.delete(test_key)
        except Exception as e:
            metrics["cache_health"] = f"error: {str(e)}"

        return JsonResponse(metrics)


@method_decorator(staff_member_required, name="dispatch")
class CacheStatsAPIView(View):
    """
    Detailed cache statistics endpoint.
    """

    def get(self, request) -> JsonResponse:
        stats = {}

        for cache_name in settings.CACHES:
            try:
                cache = caches[cache_name]
                cache_backend = cache.__class__.__name__

                cache_info = {"backend": cache_backend}

                if "Redis" in cache_backend:
                    try:
                        client = cache._cache.get_client()
                        info = client.info()

                        cache_info.update(
                            {
                                "used_memory": info.get("used_memory_human"),
                                "connected_clients": info.get("connected_clients"),
                                "keyspace_hits": info.get("keyspace_hits", 0),
                                "keyspace_misses": info.get("keyspace_misses", 0),
                                "expired_keys": info.get("expired_keys", 0),
                                "evicted_keys": info.get("evicted_keys", 0),
                                "total_connections_received": info.get("total_connections_received"),
                                "total_commands_processed": info.get("total_commands_processed"),
                            }
                        )

                        # Calculate metrics
                        hits = info.get("keyspace_hits", 0)
                        misses = info.get("keyspace_misses", 0)
                        if hits + misses > 0:
                            cache_info["hit_rate"] = round(hits / (hits + misses) * 100, 2)

                    except Exception as e:
                        cache_info["redis_error"] = str(e)

                stats[cache_name] = cache_info

            except Exception as e:
                stats[cache_name] = {"error": str(e)}

        return JsonResponse(stats)
