"""
API Key Authentication for Clients
"""
from datetime import datetime
from typing import Optional, Tuple
from fastapi import HTTPException, status, Header, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.database import get_db
from app.models.client import Client, ClientAPIKey


async def verify_api_key(
        x_api_key: str = Header(..., description="Client API Key"),
        db: AsyncSession = Depends(get_db)
) -> Tuple[Client, ClientAPIKey]:
    """
    Verify API key from request header

    Usage in routes:
    @router.post("/chat")
    async def chat(client_data: Tuple[Client, ClientAPIKey] = Depends(verify_api_key)):
        client, api_key = client_data
        ...
    """
    exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Invalid or expired API key",
        headers={"WWW-Authenticate": "ApiKey"},
    )

    if not x_api_key:
        raise exception

    # Find API key in database
    result = await db.execute(
        select(ClientAPIKey).where(
            ClientAPIKey.api_key == x_api_key,
            ClientAPIKey.is_active == True
        )
    )
    api_key = result.scalar_one_or_none()

    if not api_key:
        raise exception

    # Check expiry
    if api_key.expires_at and api_key.expires_at < datetime.utcnow():
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="API key has expired"
        )

    # Get client
    result = await db.execute(
        select(Client).where(Client.id == api_key.client_id)
    )
    client = result.scalar_one_or_none()

    if not client or client.is_deleted:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Client account not found or inactive"
        )

    # Check client status
    from app.models.client import ClientStatus
    if client.status == ClientStatus.SUSPENDED:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Client account is suspended"
        )

    # Update last used timestamp
    api_key.last_used_at = datetime.utcnow()
    api_key.total_requests += 1
    await db.commit()

    return (client, api_key)


async def get_client_from_api_key(
        x_api_key: str = Header(None, description="Client API Key"),
        db: AsyncSession = Depends(get_db)
) -> Optional[Client]:
    """
    Get client from API key (optional - returns None if no key provided)
    Useful for endpoints that support both authenticated and unauthenticated access
    """
    if not x_api_key:
        return None

    try:
        client, _ = await verify_api_key(x_api_key, db)
        return client
    except HTTPException:
        return None


def check_api_permission(api_key: ClientAPIKey, permission: str) -> bool:
    """
    Check if API key has a specific permission
    """
    if not api_key.permissions:
        return False
    return permission in api_key.permissions


class APIPermissionChecker:
    """
    Dependency for checking API key permissions
    """

    def __init__(self, required_permission: str):
        self.required_permission = required_permission

    async def __call__(
            self,
            x_api_key: str = Header(...),
            db: AsyncSession = Depends(get_db)
    ) -> Tuple[Client, ClientAPIKey]:
        client, api_key = await verify_api_key(x_api_key, db)

        if not check_api_permission(api_key, self.required_permission):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"API key does not have '{self.required_permission}' permission"
            )

        return (client, api_key)


# Common permission checkers
require_chat_permission = APIPermissionChecker("chat")
require_analytics_permission = APIPermissionChecker("analytics")
require_vision_permission = APIPermissionChecker("vision")
