import asyncio
import os
import uuid

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker

from app import main
from app.config import Settings
from app.database import get_db
from app.models import Base


@pytest.fixture(scope="session")
def event_loop():
    """Create a module-scoped event loop for all async tests."""
    loop = asyncio.new_event_loop()
    yield loop
    loop.close()


@pytest.fixture(scope="session")
def test_settings():
    """Use a test-specific settings object with an in-memory SQLite database."""
    os.environ["FRONTEND_URL"] = "http://localhost"
    os.environ["DATABASE_URL"] = "sqlite+aiosqlite:///./test.db"
    os.environ["CAPTCHA_SECRET"] = "test-secret"
    os.environ["RATE_LIMIT"] = "3/hour"
    settings = Settings()
    yield settings


@pytest.fixture(scope="session")
async def test_engine(test_settings) -> AsyncEngine:
    """Create an async engine against an SQLite database for tests."""
    engine = create_async_engine(test_settings.database_url, future=True, echo=False)
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield engine
    await engine.dispose()


@pytest.fixture(scope="function")
async def db_session(test_engine: AsyncEngine):
    """Provide a transactional database session and roll back after each test."""
    async_session = sessionmaker(
        bind=test_engine,
        class_=AsyncSession,
        expire_on_commit=False,
        autoflush=False,
        future=True,
    )
    async with async_session() as session:
        yield session
        await session.rollback()


@pytest.fixture(scope="function")
async def client(db_session: AsyncSession, monkeypatch):
    """Create an AsyncClient for FastAPI and override the DB dependency."""

    async def override_get_db():
        yield db_session

    monkeypatch.setattr(main, "settings", Settings())
    main.app.dependency_overrides[get_db] = override_get_db

    transport = ASGITransport(app=main.app)
    async with AsyncClient(transport=transport, base_url="http://testserver") as ac:
        yield ac

    main.app.dependency_overrides.clear()
