from functools import lru_cache

from fastapi import Depends
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

from app.core.config import settings
from shared.auth import JWTSettings, JWTValidator, PlatformRole, has_any_role
from shared.exceptions import ForbiddenError, UnauthorizedError
from shared.security import CurrentUser

bearer_scheme = HTTPBearer(auto_error=False)


@lru_cache
def get_jwt_validator() -> JWTValidator:
    return JWTValidator(
        JWTSettings(
            keycloak_enabled=settings.keycloak_enabled,
            keycloak_server_url=settings.keycloak_server_url,
            keycloak_realm=settings.keycloak_realm,
            jwt_algorithm=settings.jwt_algorithm,
            jwt_audience=settings.jwt_audience,
            jwt_verify_signature=settings.jwt_verify_signature,
            jwt_issuer=settings.keycloak_public_realm_url,
        )
    )


async def get_current_user(
    credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
) -> CurrentUser:
    if not settings.auth_required:
        return CurrentUser(user_id="system", username="system", roles=["platform_admin"])
    if credentials is None or not credentials.credentials:
        raise UnauthorizedError("توکن احراز هویت ارائه نشده است")
    return await get_jwt_validator().validate(credentials.credentials)


def require_roles(*roles: PlatformRole | str):
    async def _checker(user: CurrentUser = Depends(get_current_user)) -> CurrentUser:
        if not settings.auth_required:
            return user
        if not has_any_role(user, *roles):
            raise ForbiddenError("دسترسی کافی برای این عملیات ندارید")
        return user

    return _checker


require_platform_admin = require_roles(PlatformRole.PLATFORM_ADMIN)
require_tenant_admin = require_roles(
    PlatformRole.PLATFORM_ADMIN, PlatformRole.TENANT_ADMIN
)
require_authenticated = get_current_user
