"""Bulk operation endpoint tests."""

from __future__ import annotations

from collections.abc import AsyncGenerator

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from tests.conftest import Book, SessionFactory

from auen import CrudRouterBuilder, Operation


@pytest.fixture
def bulk_app(get_session: SessionFactory) -> FastAPI:
    app = FastAPI()
    app.include_router(
        CrudRouterBuilder.for_model(Book, get_session)
        .with_operations(
            {
                Operation.CREATE,
                Operation.READ,
                Operation.BULK_CREATE,
                Operation.BULK_UPDATE,
                Operation.BULK_DELETE,
            }
        )
        .build()
    )
    return app


@pytest.fixture
async def bulk_client(bulk_app: FastAPI) -> AsyncGenerator[AsyncClient, None]:
    transport = ASGITransport(app=bulk_app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c


async def test_bulk_create(bulk_client: AsyncClient) -> None:
    resp = await bulk_client.post(
        "/books/bulk",
        json=[
            {"title": "Book A", "isbn": "111"},
            {"title": "Book B", "isbn": "222"},
        ],
    )
    assert resp.status_code == 201
    data = resp.json()
    assert len(data) == 2
    assert data[0]["title"] == "Book A"
    assert data[1]["title"] == "Book B"
    assert data[0]["id"] is not None


async def test_bulk_create_empty(bulk_client: AsyncClient) -> None:
    resp = await bulk_client.post("/books/bulk", json=[])
    assert resp.status_code == 201
    assert resp.json() == []


async def test_bulk_update(bulk_client: AsyncClient) -> None:
    # Create books first
    resp = await bulk_client.post(
        "/books/bulk",
        json=[
            {"title": "Old A", "isbn": "111"},
            {"title": "Old B", "isbn": "222"},
        ],
    )
    books = resp.json()

    # Send back full ReadSchema objects with changed fields
    books[0]["title"] = "New A"
    books[1]["title"] = "New B"
    resp = await bulk_client.patch(
        "/books/bulk",
        json=books,
    )
    assert resp.status_code == 200
    data = resp.json()
    assert data[0]["title"] == "New A"
    assert data[1]["title"] == "New B"


async def test_bulk_update_not_found(bulk_client: AsyncClient) -> None:
    resp = await bulk_client.patch(
        "/books/bulk",
        json=[{"id": 9999, "title": "Nope", "isbn": "X", "pages": None}],
    )
    assert resp.status_code == 404


async def test_bulk_delete(bulk_client: AsyncClient) -> None:
    resp = await bulk_client.post(
        "/books/bulk",
        json=[
            {"title": "Del A", "isbn": "333"},
            {"title": "Del B", "isbn": "444"},
        ],
    )
    books = resp.json()

    resp = await bulk_client.request(
        "DELETE",
        "/books/bulk",
        json=[{"id": books[0]["id"]}, {"id": books[1]["id"]}],
    )
    assert resp.status_code == 200

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


async def test_bulk_delete_not_found(bulk_client: AsyncClient) -> None:
    resp = await bulk_client.request(
        "DELETE",
        "/books/bulk",
        json=[{"id": 9999}],
    )
    assert resp.status_code == 404
