"""Shared pytest fixtures."""

from __future__ import annotations

import uuid
from collections.abc import AsyncIterator

import pytest
from fastapi import Depends, FastAPI
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.pool import StaticPool

from aura_auth._core.security import PasswordHelper, TokenHelper
from aura_auth.app import AuraAuth
from aura_auth.backend.sqlalchemy import SQLAlchemyBackend
from aura_auth.manager import UserManager
from aura_auth.models.sqlalchemy import Base, SQLAlchemyBaseUser
from aura_auth.strategies.password import PasswordStrategy


@pytest.fixture
async def engine() -> AsyncIterator[AsyncEngine]:
    eng = create_async_engine(
        "sqlite+aiosqlite://",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    async with eng.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield eng
    await eng.dispose()


@pytest.fixture
def session_factory(engine: AsyncEngine) -> async_sessionmaker[AsyncSession]:
    return async_sessionmaker(engine, expire_on_commit=False)


@pytest.fixture
def aura_auth(engine: AsyncEngine) -> AuraAuth:
    return AuraAuth(
        database_url="sqlite+aiosqlite://",
        secret="test-secret-" + str(uuid.uuid4()),
        engine=engine,
    )


@pytest.fixture
def manager(session_factory: async_sessionmaker[AsyncSession]) -> UserManager:
    backend = SQLAlchemyBackend(session_factory, SQLAlchemyBaseUser)
    password_helper = PasswordHelper()
    token_helper = TokenHelper("u" * 32, lifetime_seconds=3600)
    verify_helper = TokenHelper("u" * 32, lifetime_seconds=3600)
    strategy = PasswordStrategy(password_helper, token_helper)
    return UserManager(backend, strategy, token_helper, verify_helper)


@pytest.fixture
def app(aura_auth: AuraAuth) -> FastAPI:
    application = FastAPI()
    aura_auth.init_app(application)

    @application.get("/protected")
    async def protected(user=Depends(aura_auth.current_user())):
        return {"email": user.email}

    @application.get("/active-only")
    async def active_only(user=Depends(aura_auth.current_active_user())):
        return {"email": user.email}

    @application.get("/verified-only")
    async def verified_only(user=Depends(aura_auth.current_verified_user())):
        return {"email": user.email}

    return application
