"""Tests for OpenAPI customization (operation IDs, include_in_schema)."""

from __future__ import annotations

from collections.abc import AsyncGenerator

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

from auen import CrudRouterBuilder, Operation


@pytest.fixture
def custom_opid_app(get_session: SessionFactory) -> FastAPI:
    application = FastAPI()
    application.include_router(
        CrudRouterBuilder.for_model(
            __import__("tests.conftest", fromlist=["Book"]).Book,
            get_session,
        )
        .with_operation_id_prefix("books_v2")
        .build()
    )
    return application


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


async def test_custom_operation_ids(custom_opid_client: AsyncClient) -> None:
    resp = await custom_opid_client.get("/openapi.json")
    schema = resp.json()
    op_ids = []
    for path_item in schema["paths"].values():
        for method_info in path_item.values():
            if "operationId" in method_info:
                op_ids.append(method_info["operationId"])
    assert "books_v2_create" in op_ids
    assert "books_v2_nested_create" in op_ids
    assert "books_v2_list" in op_ids
    assert "books_v2_read" in op_ids
    assert "books_v2_update" in op_ids
    assert "books_v2_nested_update" in op_ids
    assert "books_v2_delete" in op_ids


@pytest.fixture
def hidden_ops_app(get_session: SessionFactory) -> FastAPI:
    from tests.conftest import Book

    application = FastAPI()
    application.include_router(
        CrudRouterBuilder.for_model(Book, get_session)
        .with_include_in_schema({Operation.LIST, Operation.READ})
        .build()
    )
    return application


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


async def test_include_in_schema_hides_operations(
    hidden_ops_client: AsyncClient,
) -> None:
    """Operations not in include_in_schema should be absent from OpenAPI."""
    resp = await hidden_ops_client.get("/openapi.json")
    schema = resp.json()

    # The endpoints still work, but they're hidden from the schema
    methods_in_schema = set()
    for path_item in schema["paths"].values():
        methods_in_schema.update(path_item.keys())

    assert "get" in methods_in_schema  # LIST and READ are visible
    assert "post" not in methods_in_schema  # CREATE hidden
    assert "patch" not in methods_in_schema  # UPDATE hidden
    assert "delete" not in methods_in_schema  # DELETE hidden

    # But the endpoints still work
    resp = await hidden_ops_client.post("/books/", json={"title": "Test", "isbn": "123"})
    assert resp.status_code == 201
