"""Test that the README quickstart example works end-to-end."""

from __future__ import annotations

from collections.abc import AsyncGenerator

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

from auen import CrudRouterBuilder


class Author(SQLModel, table=True):
    __tablename__ = "readme_author"
    id: int | None = Field(default=None, primary_key=True)
    name: str
    bio: str | None = None


class Book(SQLModel, table=True):
    __tablename__ = "readme_book"
    id: int | None = Field(default=None, primary_key=True)
    title: str
    isbn: str
    author_id: int | None = Field(default=None, foreign_key="readme_author.id")


@pytest.fixture
async def readme_app() -> AsyncGenerator[FastAPI, None]:
    engine = create_async_engine(
        "sqlite+aiosqlite://",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)

    async def get_session() -> AsyncGenerator[AsyncSession, None]:
        async with AsyncSession(engine) as session:
            yield session

    app = FastAPI()
    for router in CrudRouterBuilder.for_model([Author, Book], get_session).build_all():
        app.include_router(router)

    yield app
    await engine.dispose()


async def test_readme_quickstart_roundtrip(readme_app: FastAPI) -> None:
    transport = ASGITransport(app=readme_app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        # Create an author
        resp = await c.post(
            "/authors/",
            json={"name": "Robert C. Martin", "bio": "Author of Clean Code"},
        )
        assert resp.status_code == 201
        author = resp.json()
        author_id = author["id"]
        assert author["name"] == "Robert C. Martin"

        # Create a book linked to the author
        resp = await c.post(
            "/books/",
            json={
                "title": "Clean Code",
                "isbn": "978-0132350884",
                "author_id": author_id,
            },
        )
        assert resp.status_code == 201
        book = resp.json()
        assert book["title"] == "Clean Code"
        assert book["author_id"] == author_id

        # List authors
        resp = await c.get("/authors/")
        assert resp.status_code == 200
        assert len(resp.json()) == 1

        # List books
        resp = await c.get("/books/")
        assert resp.status_code == 200
        assert len(resp.json()) == 1

        # Read single book
        resp = await c.get(f"/books/{book['id']}")
        assert resp.status_code == 200
        assert resp.json()["isbn"] == "978-0132350884"

        # Update book
        resp = await c.patch(
            f"/books/{book['id']}",
            json={"title": "Clean Code: A Handbook of Agile Software Craftsmanship"},
        )
        assert resp.status_code == 200
        assert resp.json()["title"].startswith("Clean Code: A Handbook")

        # Delete book
        resp = await c.delete(f"/books/{book['id']}")
        assert resp.status_code == 200

        # Verify deleted
        resp = await c.get(f"/books/{book['id']}")
        assert resp.status_code == 404
