"""
API Versioning Strategy
Supports multiple API versions with header-based and URL-based versioning
"""
from typing import Optional, Callable
from enum import Enum
from functools import wraps
from fastapi import APIRouter, Request, HTTPException, Header
from fastapi.routing import APIRoute
import logging

logger = logging.getLogger(__name__)


class APIVersion(str, Enum):
    """Supported API versions"""
    V1 = "v1"
    V2 = "v2"
    V3 = "v3"

    @classmethod
    def latest(cls) -> "APIVersion":
        return cls.V1  # Current latest stable version

    @classmethod
    def all_versions(cls) -> list:
        return [v.value for v in cls]


class VersionedAPIRouter(APIRouter):
    """
    Extended APIRouter with versioning support
    """

    def __init__(self, version: APIVersion, *args, **kwargs):
        self.api_version = version
        super().__init__(*args, **kwargs)

    def api_route(self, path: str, *args, **kwargs):
        """Override to add version info to route"""
        def decorator(func):
            # Add version metadata
            func._api_version = self.api_version
            return super(VersionedAPIRouter, self).api_route(path, *args, **kwargs)(func)
        return decorator


def get_api_version(
    x_api_version: Optional[str] = Header(None, alias="X-API-Version"),
    accept_version: Optional[str] = Header(None, alias="Accept-Version")
) -> APIVersion:
    """
    Extract API version from headers

    Priority:
    1. X-API-Version header
    2. Accept-Version header
    3. Default to latest version
    """
    version_str = x_api_version or accept_version

    if version_str:
        # Remove 'v' prefix if present
        version_str = version_str.lower().strip()
        if not version_str.startswith("v"):
            version_str = f"v{version_str}"

        try:
            return APIVersion(version_str)
        except ValueError:
            logger.warning(f"Invalid API version requested: {version_str}")
            raise HTTPException(
                status_code=400,
                detail={
                    "error": "invalid_api_version",
                    "message": f"Invalid API version: {version_str}",
                    "supported_versions": APIVersion.all_versions(),
                    "latest_version": APIVersion.latest().value
                }
            )

    return APIVersion.latest()


def deprecated(
    message: str = "This endpoint is deprecated",
    sunset_date: Optional[str] = None,
    alternative: Optional[str] = None
):
    """
    Decorator to mark endpoints as deprecated

    Adds deprecation headers to response
    """
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            response = await func(*args, **kwargs)

            # Get the request from args
            request = None
            for arg in args:
                if isinstance(arg, Request):
                    request = arg
                    break

            # Add deprecation info to response headers if possible
            deprecation_info = {
                "warning": f'299 - "{message}"',
            }
            if sunset_date:
                deprecation_info["Sunset"] = sunset_date
            if alternative:
                deprecation_info["Link"] = f'<{alternative}>; rel="successor-version"'

            # Log deprecation usage
            if request:
                logger.warning(
                    f"Deprecated endpoint accessed: {request.url.path} - {message}"
                )

            return response
        return wrapper
    return decorator


def version_range(min_version: APIVersion, max_version: Optional[APIVersion] = None):
    """
    Decorator to restrict endpoint to specific version range

    Usage:
        @version_range(APIVersion.V1, APIVersion.V2)
        async def my_endpoint():
            ...
    """
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, api_version: APIVersion = APIVersion.latest(), **kwargs):
            versions = list(APIVersion)
            min_idx = versions.index(min_version)
            max_idx = versions.index(max_version) if max_version else len(versions) - 1
            current_idx = versions.index(api_version)

            if current_idx < min_idx or current_idx > max_idx:
                raise HTTPException(
                    status_code=400,
                    detail={
                        "error": "version_not_supported",
                        "message": f"This endpoint is not available in API version {api_version.value}",
                        "available_versions": [v.value for v in versions[min_idx:max_idx + 1]]
                    }
                )

            return await func(*args, **kwargs)
        return wrapper
    return decorator


class VersionMiddleware:
    """
    Middleware to handle API versioning at the application level
    """

    def __init__(self, app, default_version: APIVersion = APIVersion.V1):
        self.app = app
        self.default_version = default_version

    async def __call__(self, scope, receive, send):
        if scope["type"] == "http":
            # Extract version from headers
            headers = dict(scope.get("headers", []))
            version = headers.get(b"x-api-version", b"").decode()

            if not version:
                version = headers.get(b"accept-version", b"").decode()

            if not version:
                version = self.default_version.value

            # Add version to scope for downstream access
            scope["api_version"] = version

        await self.app(scope, receive, send)


# Version-specific response transformers
class ResponseTransformer:
    """
    Transform responses based on API version for backward compatibility
    """

    @staticmethod
    def transform_v1_to_v2(data: dict) -> dict:
        """Transform V1 response format to V2"""
        # Example transformation
        return data

    @staticmethod
    def transform_v2_to_v1(data: dict) -> dict:
        """Transform V2 response format to V1 for backward compatibility"""
        # Example transformation
        return data


# API Version documentation
API_VERSION_DOCS = {
    "v1": {
        "release_date": "2024-01-01",
        "status": "stable",
        "description": "Initial stable API release",
        "changelog": [
            "Chat endpoints",
            "Webhook management",
            "Authentication",
            "Billing"
        ]
    },
    "v2": {
        "release_date": "2024-06-01",
        "status": "beta",
        "description": "Enhanced API with GraphQL support",
        "changelog": [
            "GraphQL endpoint",
            "Bulk operations",
            "Enhanced filtering",
            "Improved pagination"
        ]
    },
    "v3": {
        "release_date": "2025-01-01",
        "status": "alpha",
        "description": "Next generation API",
        "changelog": [
            "Real-time streaming",
            "Advanced analytics",
            "Multi-tenant improvements"
        ]
    }
}
