"""用户身份、授权与认证服务依赖。"""

from typing import Any, cast

from fastapi import Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session

from app.adapters.web.security.access import verify_token
from app.api.context import get_async_session, get_host_runtime, get_sync_session
from app.application.security.auth import (
    AuthConfigRepository,
    AuthPasskeyRepository,
    AuthService,
    AuthUserRepository,
)
from app.application.security.passkeys import PasskeyRepository, PasskeyService
from app.application.security.user import (
    AsyncUnitOfWork,
    UserRepository,
    UserService,
)
from app.schemas.token import TokenPayload as _SchemaTokenPayload
from app.startup.composition.context import HostRuntime


def get_user_service(
    db: AsyncSession = Depends(get_async_session),
    runtime: HostRuntime = Depends(get_host_runtime),
) -> UserService:
    """组装用户管理应用服务。"""
    return UserService(
        repository=cast(
            UserRepository, runtime.authentication.user_repository(db)
        ),
        unit_of_work=cast(
            AsyncUnitOfWork, runtime.persistence.async_transaction(db)
        ),
    )


def get_auth_service(
    runtime: HostRuntime = Depends(get_host_runtime),
) -> AuthService:
    """组装同步认证应用服务。"""
    return AuthService(
        users=cast(AuthUserRepository, runtime.authentication.standalone_user()),
        config=cast(AuthConfigRepository, runtime.authentication.system_config()),
        passkeys=cast(AuthPasskeyRepository, runtime.authentication.passkey()),
    )


def get_passkey_service(
    runtime: HostRuntime = Depends(get_host_runtime),
) -> PasskeyService:
    """组装 PassKey 应用服务。"""
    return PasskeyService(repository=cast(
        PasskeyRepository, runtime.authentication.passkey()
    ))


def get_current_user(
    db: Session = Depends(get_sync_session),
    token_data: _SchemaTokenPayload = Depends(verify_token),
    runtime: HostRuntime = Depends(get_host_runtime),
) -> Any:
    """读取令牌对应用户，不存在时返回 403。"""
    user_repository = cast(
        AuthUserRepository, runtime.authentication.user_repository(db)
    )
    user = user_repository.get_by_id(token_data.sub)
    if not user:
        raise HTTPException(status_code=403, detail="用户不存在")
    return user


async def get_current_user_async(
    db: AsyncSession = Depends(get_async_session),
    token_data: _SchemaTokenPayload = Depends(verify_token),
    runtime: HostRuntime = Depends(get_host_runtime),
) -> Any:
    """异步读取令牌对应用户，不存在时返回 403。"""
    user_repository = cast(
        UserRepository, runtime.authentication.user_repository(db)
    )
    user = await user_repository.async_get_by_id(token_data.sub)
    if not user:
        raise HTTPException(status_code=403, detail="用户不存在")
    return user


def get_current_active_user(
    current_user: Any = Depends(get_current_user),
) -> Any:
    """校验并返回当前激活用户。"""
    if not current_user.is_active:
        raise HTTPException(status_code=403, detail="用户未激活")
    return current_user


async def get_current_active_user_async(
    current_user: Any = Depends(get_current_user_async),
) -> Any:
    """异步校验并返回当前激活用户。"""
    if not current_user.is_active:
        raise HTTPException(status_code=403, detail="用户未激活")
    return current_user


def _ensure_manage_user(current_user: Any) -> Any:
    """校验用户具备全局管理权限。"""
    permissions = current_user.permissions or {}
    if not current_user.is_superuser and not bool(permissions.get("manage")):
        raise HTTPException(status_code=400, detail="用户权限不足")
    return current_user


def get_current_active_manage_user(
    current_user: Any = Depends(get_current_active_user),
) -> Any:
    """返回当前拥有管理权限的激活用户。"""
    return _ensure_manage_user(current_user)


async def get_current_active_manage_user_async(
    current_user: Any = Depends(get_current_active_user_async),
) -> Any:
    """异步返回当前拥有管理权限的激活用户。"""
    return _ensure_manage_user(current_user)


def get_current_active_superuser(
    current_user: Any = Depends(get_current_user),
) -> Any:
    """校验并返回当前激活超级管理员。"""
    if not current_user.is_superuser:
        raise HTTPException(status_code=400, detail="用户权限不足")
    return current_user


async def get_current_active_superuser_async(
    current_user: Any = Depends(get_current_user_async),
) -> Any:
    """异步校验并返回当前激活超级管理员。"""
    if not current_user.is_superuser:
        raise HTTPException(status_code=400, detail="用户权限不足")
    return current_user
