import logging
import time
from datetime import datetime, timedelta, timezone
from typing import Any

import aiohttp
import jwt
from fastapi import Depends, HTTPException
from prometheus_client import Counter, Gauge, Histogram
from sqlalchemy.orm import Session

from src.config import get_settings
from src.utils.base_classes import BaseService

from ..database import get_db
from ..models.api_call import APICall, APIUsage
from ..models.user import User
from ..quantum_py.intelligence.market_intelligence import MarketIntelligence
from ..quantum_py.intelligence.quantum_intelligence import QuantumIntelligence
from ..quantum_py.intelligence.strategic_intelligence import StrategicIntelligence

# Prometheus metrics
api_calls_total = Counter(
    "api_calls_total", "Total number of API calls", ["endpoint", "status"]
)
api_response_time = Histogram(
    "api_response_time_seconds", "API response time in seconds", ["endpoint"]
)
api_errors_total = Counter(
    "api_errors_total", "Total number of API errors", ["endpoint", "error_type"]
)
active_users = Gauge("active_users", "Number of active users")
api_usage_gauge = Gauge("api_usage", "Current API usage", ["user_id", "plan"])


class APIService(BaseService):
    """Service for handling API operations."""

    def __init__(self, db: Session = Depends(get_db)):
        """Initialize API service."""
        super().__init__(db)
        self.settings = get_settings()
        self.start_time = time.time()
        self.market_intelligence = MarketIntelligence()
        self.strategic_intelligence = StrategicIntelligence()
        self.quantum_intelligence = QuantumIntelligence()
        self.logger = logging.getLogger(__name__)

    async def validate_api_key(self, api_key: str) -> User:
        """Validate API key and return user."""
        try:
            payload = jwt.decode(
                api_key,
                self.settings.SECRET_KEY,
                algorithms=["HS256"],
            )
            user_id = payload.get("sub")
            if not user_id:
                raise HTTPException(status_code=401, detail="Invalid API key")

            user = self.db.query(User).filter(User.id == user_id).first()
            if not user:
                raise HTTPException(status_code=401, detail="User not found")

            if not user.is_active:
                raise HTTPException(status_code=401, detail="User account is inactive")

            return user
        except jwt.InvalidTokenError:
            raise HTTPException(status_code=401, detail="Invalid API key")

    async def check_rate_limit(self, user: User) -> bool:
        """Check if user has exceeded rate limit"""
        current_time = datetime.now(timezone.utc)
        recent_calls = (
            self.db.query(APICall)
            .filter(
                APICall.user_id == user.id,
                APICall.timestamp >= current_time - timedelta(minutes=1),
            )
            .count()
        )

        return recent_calls < user.subscription.rate_limit

    async def check_usage_limit(self, user: User) -> bool:
        """Check if user has exceeded monthly usage limit"""
        current_period_start = user.subscription.current_period_start
        current_period_end = user.subscription.current_period_end

        monthly_usage = (
            self.db.query(APIUsage)
            .filter(
                APIUsage.user_id == user.id,
                APIUsage.timestamp >= current_period_start,
                APIUsage.timestamp <= current_period_end,
            )
            .first()
        )

        if not monthly_usage:
            return True

        return monthly_usage.calls_count < user.subscription.api_calls_limit

    async def track_api_call(
        self, user: User, endpoint: str, response_time: float, status: int
    ):
        """Track API call metrics"""
        # Update Prometheus metrics
        api_calls_total.labels(endpoint=endpoint, status=str(status)).inc()
        api_response_time.labels(endpoint=endpoint).observe(response_time)
        if status >= 400:
            api_errors_total.labels(endpoint=endpoint, error_type=str(status)).inc()

        # Update database
        api_call = APICall(
            user_id=user.id,
            endpoint=endpoint,
            response_time=response_time,
            status=status,
            timestamp=datetime.now(timezone.utc),
        )
        self.db.add(api_call)

        # Update monthly usage
        monthly_usage = (
            self.db.query(APIUsage)
            .filter(
                APIUsage.user_id == user.id,
                APIUsage.timestamp >= user.subscription.current_period_start,
                APIUsage.timestamp <= user.subscription.current_period_end,
            )
            .first()
        )

        if not monthly_usage:
            monthly_usage = APIUsage(
                user_id=user.id, calls_count=0, timestamp=datetime.now(timezone.utc)
            )
            self.db.add(monthly_usage)

        monthly_usage.calls_count += 1
        self.db.commit()

        # Update Prometheus gauge
        api_usage_gauge.labels(
            user_id=str(user.id), plan=user.subscription.plan_type
        ).set(monthly_usage.calls_count)

    async def get_usage_analytics(self, user: User) -> dict:
        """Get detailed usage analytics for user"""
        current_period_start = user.subscription.current_period_start
        current_period_end = user.subscription.current_period_end

        # Get daily usage
        daily_usage = (
            self.db.query(APICall)
            .filter(
                APICall.user_id == user.id,
                APICall.timestamp >= current_period_start,
                APICall.timestamp <= current_period_end,
            )
            .all()
        )

        # Calculate response time distribution
        response_times = [call.response_time for call in daily_usage]
        response_time_distribution = {
            "<100ms": len([t for t in response_times if t < 0.1]),
            "100-200ms": len([t for t in response_times if 0.1 <= t < 0.2]),
            "200-300ms": len([t for t in response_times if 0.2 <= t < 0.3]),
            "300-400ms": len([t for t in response_times if 0.3 <= t < 0.4]),
            ">400ms": len([t for t in response_times if t >= 0.4]),
        }

        # Get endpoint usage
        endpoint_usage: dict[str, int] = {}
        for call in daily_usage:
            endpoint_usage[call.endpoint] = endpoint_usage.get(call.endpoint, 0) + 1

        # Get error rates
        error_calls = [call for call in daily_usage if call.status >= 400]
        error_rate = len(error_calls) / len(daily_usage) if daily_usage else 0

        return {
            "total_calls": len(daily_usage),
            "response_time_distribution": response_time_distribution,
            "endpoint_usage": endpoint_usage,
            "error_rate": error_rate,
            "average_response_time": (
                sum(response_times) / len(response_times) if response_times else 0
            ),
        }

    async def get_advanced_analytics(self, user: User) -> dict:
        """Get advanced analytics for enterprise users"""
        if user.subscription.plan_type != "ENTERPRISE":
            raise HTTPException(
                status_code=403,
                detail="Advanced analytics only available for Enterprise plan",
            )

        # Get market intelligence
        market_data = await self.market_intelligence.get_market_analysis()

        # Get strategic insights
        strategic_insights = await self.strategic_intelligence.get_strategic_insights()

        # Get quantum analysis
        quantum_analysis = await self.quantum_intelligence.get_quantum_analysis()

        return {
            "market_intelligence": market_data,
            "strategic_insights": strategic_insights,
            "quantum_analysis": quantum_analysis,
        }

    async def get_user_dashboard_data(self, user: User) -> dict:
        """Get all dashboard data for user"""
        usage_analytics = await self.get_usage_analytics(user)

        dashboard_data = {
            "user": {
                "email": user.email,
                "plan_type": user.subscription.plan_type,
                "api_key": user.api_key,
            },
            "subscription": {
                "current_period_start": user.subscription.current_period_start,
                "current_period_end": user.subscription.current_period_end,
                "api_calls_limit": user.subscription.api_calls_limit,
                "rate_limit": user.subscription.rate_limit,
            },
            "usage": {
                "calls_remaining": user.subscription.api_calls_limit
                - usage_analytics["total_calls"],
                "current_usage": usage_analytics["total_calls"],
                "response_time_distribution": usage_analytics[
                    "response_time_distribution"
                ],
                "endpoint_usage": usage_analytics["endpoint_usage"],
                "error_rate": usage_analytics["error_rate"],
                "average_response_time": usage_analytics["average_response_time"],
            },
        }

        # Add advanced analytics for enterprise users
        if user.subscription.plan_type == "ENTERPRISE":
            advanced_analytics = await self.get_advanced_analytics(user)
            dashboard_data["advanced_analytics"] = advanced_analytics

        return dashboard_data

    async def monitor_api_health(self) -> dict:
        """Monitor overall API health"""
        # Get system metrics
        system_metrics = {
            "uptime": time.time() - self.start_time,
            "active_users": active_users._value.get(),
            "total_api_calls": api_calls_total._value.get(),
            "error_rate": (
                api_errors_total._value.get() / api_calls_total._value.get()
                if api_calls_total._value.get() > 0
                else 0
            ),
        }

        # Get database health
        try:
            self.db.execute("SELECT 1")
            db_health = "healthy"
        except Exception as e:
            db_health = "unhealthy"
            self.logger.error(f"Database health check failed: {str(e)}")

        # Get external service health
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(
                    self.settings.QUANTUM_SERVICE_URL + "/health"
                ) as response:
                    quantum_health = (
                        "healthy" if response.status == 200 else "unhealthy"
                    )
            except Exception as e:
                quantum_health = "unhealthy"
                self.logger.error(f"Quantum service health check failed: {str(e)}")

        return {
            "system_metrics": system_metrics,
            "database_health": db_health,
            "quantum_service_health": quantum_health,
            "timestamp": datetime.now(timezone.utc).isoformat(),
        }

    async def optimize_api_performance(self) -> dict:
        """Optimize API performance based on usage patterns"""
        # Get recent API calls
        recent_calls = (
            self.db.query(APICall)
            .filter(
                APICall.timestamp >= datetime.now(timezone.utc) - timedelta(hours=24)
            )
            .all()
        )

        # Analyze response times
        response_times = [call.response_time for call in recent_calls]
        avg_response_time = (
            sum(response_times) / len(response_times) if response_times else 0
        )

        # Identify slow endpoints
        endpoint_times: dict[str, list[float]] = {}
        for call in recent_calls:
            if call.endpoint not in endpoint_times:
                endpoint_times[call.endpoint] = []
            endpoint_times[call.endpoint].append(call.response_time)

        slow_endpoints = {
            endpoint: sum(times) / len(times)
            for endpoint, times in endpoint_times.items()
            if sum(times) / len(times) > avg_response_time * 1.5
        }

        # Generate optimization recommendations
        recommendations = []
        for endpoint, avg_time in slow_endpoints.items():
            if avg_time > 1.0:  # More than 1 second
                recommendations.append(
                    {
                        "endpoint": endpoint,
                        "issue": "High response time",
                        "recommendation": "Implement caching and optimize "
                        "database queries",
                    }
                )
            elif avg_time > 0.5:  # More than 500ms
                recommendations.append(
                    {
                        "endpoint": endpoint,
                        "issue": "Moderate response time",
                        "recommendation": "Consider implementing request batching",
                    }
                )

        return {
            "average_response_time": avg_response_time,
            "slow_endpoints": slow_endpoints,
            "recommendations": recommendations,
            "timestamp": datetime.now(timezone.utc).isoformat(),
        }

    def execute(self, *args, **kwargs) -> Any:
        """Execute API service operation.

        Args:
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments

        Returns:
            Any: Result of the API operation
        """
        # Default implementation - can be overridden by subclasses
        return {"status": "api_processed", "service": "api"}
