from collections.abc import AsyncGenerator

from fastapi import Depends, Header, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession

from app.auth.jwt_provider import JWTAuthProvider
from app.auth.provider import AuthProvider, Identity
from app.database import get_session_factory
from app.storage.backend import StorageBackend
from app.storage.s3_backend import S3StorageBackend

_storage: StorageBackend | None = None
_auth: AuthProvider | None = None


def get_storage() -> StorageBackend:
    global _storage
    if _storage is None:
        _storage = S3StorageBackend()
    return _storage


def get_auth() -> AuthProvider:
    global _auth
    if _auth is None:
        from app.config import get_settings

        s = get_settings()
        _auth = JWTAuthProvider(
            secret_key=s.jwt_secret_key,
            expiry_seconds=s.jwt_expiry_seconds,
            owner_username=s.owner_username,
            owner_password=s.owner_password,
        )
    return _auth


def get_jwt_auth() -> JWTAuthProvider:
    auth = get_auth()
    assert isinstance(auth, JWTAuthProvider)
    return auth


async def require_auth(
    authorization: str | None = Header(None, alias="Authorization"),
    auth: AuthProvider = Depends(get_auth),
) -> Identity:
    identity = await auth.get_identity(authorization)
    if identity.anonymous:
        raise HTTPException(
            status_code=401,
            detail={"detail": "Authentication required", "code": "unauthorized"},
        )
    return identity


async def get_db() -> AsyncGenerator[AsyncSession, None]:
    factory = get_session_factory()
    async with factory() as session, session.begin():
        yield session
