"""Filter operation tests."""

from __future__ import annotations

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

from auen import CrudRouterBuilder, FilterConfig, FilterFieldConfig, FilterOp, Operation


async def test_filter_gt(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "Short", "isbn": "ISBN-1", "pages": 100},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Medium", "isbn": "ISBN-2", "pages": 200},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Long", "isbn": "ISBN-3", "pages": 300},
    )

    resp = await filter_ops_client.get("/books/?pages__gt=150&sort=pages")
    assert resp.status_code == 200
    pages = [b["pages"] for b in resp.json()]
    assert pages == [200, 300]


async def test_filter_contains(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "Clean Code", "isbn": "ISBN-1"},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Algorithms", "isbn": "ISBN-2"},
    )

    resp = await filter_ops_client.get("/books/?title__contains=Code")
    assert resp.status_code == 200
    titles = [b["title"] for b in resp.json()]
    assert titles == ["Clean Code"]


async def test_filter_lt(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "Short", "isbn": "ISBN-1", "pages": 100},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Long", "isbn": "ISBN-2", "pages": 300},
    )

    resp = await filter_ops_client.get("/books/?pages__lt=200&sort=pages")
    assert resp.status_code == 200
    pages = [b["pages"] for b in resp.json()]
    assert pages == [100]


async def test_filter_lte(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "Short", "isbn": "ISBN-1", "pages": 100},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Medium", "isbn": "ISBN-2", "pages": 200},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Long", "isbn": "ISBN-3", "pages": 300},
    )

    resp = await filter_ops_client.get("/books/?pages__lte=200&sort=pages")
    assert resp.status_code == 200
    pages = [b["pages"] for b in resp.json()]
    assert pages == [100, 200]


async def test_filter_gte(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "Short", "isbn": "ISBN-1", "pages": 100},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Medium", "isbn": "ISBN-2", "pages": 200},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Long", "isbn": "ISBN-3", "pages": 300},
    )

    resp = await filter_ops_client.get("/books/?pages__gte=200&sort=pages")
    assert resp.status_code == 200
    pages = [b["pages"] for b in resp.json()]
    assert pages == [200, 300]


async def test_filter_in(filter_ops_client: AsyncClient) -> None:
    await filter_ops_client.post(
        "/books/",
        json={"title": "One", "isbn": "ISBN-1", "pages": 111},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Two", "isbn": "ISBN-2", "pages": 222},
    )
    await filter_ops_client.post(
        "/books/",
        json={"title": "Three", "isbn": "ISBN-3", "pages": 333},
    )

    resp = await filter_ops_client.get("/books/?pages__in=111,333&sort=pages")
    assert resp.status_code == 200
    pages = [b["pages"] for b in resp.json()]
    assert pages == [111, 333]


async def test_icontains_filter(get_session: SessionFactory) -> None:
    app = FastAPI()
    app.include_router(
        CrudRouterBuilder.for_model(Book, get_session)
        .with_filters(
            FilterConfig(
                fields={
                    "title": FilterFieldConfig(ops=frozenset({FilterOp.ICONTAINS})),
                },
            )
        )
        .with_operations({Operation.CREATE, Operation.LIST})
        .build()
    )
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        await c.post("/books/", json={"title": "Hello World", "isbn": "1"})
        resp = await c.get("/books/", params={"title__icontains": "hello"})
        assert resp.status_code == 200
        assert len(resp.json()) == 1
