"""Simple test for async support."""

from __future__ import annotations

from collections.abc import AsyncGenerator, Callable

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
from sqlmodel import Field, SQLModel
from sqlmodel.ext.asyncio.session import AsyncSession

from auen import CrudRouterBuilder, derive_schemas


class AsyncItem(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str


@pytest.fixture
async def async_engine() -> AsyncEngine:
    eng = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        echo=False,
    )
    async with eng.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)
    return eng


@pytest.fixture
async def async_get_session(
    async_engine: AsyncEngine,
) -> Callable[[], AsyncGenerator[AsyncSession, None]]:
    async def _get_session() -> AsyncGenerator[AsyncSession, None]:
        async with AsyncSession(async_engine) as session:
            yield session

    return _get_session


@pytest.fixture
def async_app(
    async_get_session: Callable[[], AsyncGenerator[AsyncSession, None]],
) -> FastAPI:
    """Async app with async endpoints."""
    application = FastAPI()

    application.include_router(
        CrudRouterBuilder.for_model(AsyncItem, async_get_session)
        .with_schemas(derive_schemas(AsyncItem))
        .build()
    )
    return application


@pytest.mark.asyncio
async def test_async_create(async_app: FastAPI) -> None:
    """Test async CREATE operation."""
    transport = ASGITransport(app=async_app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.post("/asyncitems/", json={"name": "test"})
        assert resp.status_code == 201
        item = resp.json()
        assert item["name"] == "test"
        assert "id" in item


@pytest.mark.asyncio
async def test_async_read(async_app: FastAPI) -> None:
    """Test async READ operation."""
    transport = ASGITransport(app=async_app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        # Create an item first
        resp = await client.post("/asyncitems/", json={"name": "test"})
        item_id = resp.json()["id"]

        # Read it back
        resp = await client.get(f"/asyncitems/{item_id}")
        assert resp.status_code == 200
        assert resp.json()["name"] == "test"


@pytest.mark.asyncio
async def test_async_list(async_app: FastAPI) -> None:
    """Test async LIST operation."""
    transport = ASGITransport(app=async_app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        # Create multiple items
        for i in range(3):
            await client.post("/asyncitems/", json={"name": f"item{i}"})

        # List them
        resp = await client.get("/asyncitems/")
        assert resp.status_code == 200
        items = resp.json()
        assert len(items) == 3
        assert all("id" in item and "name" in item for item in items)
