from fastapi import FastAPI, HTTPException, status
from fastapi.testclient import TestClient
from sqlalchemy.exc import SQLAlchemyError

from src.core.exception_handlers import register_exception_handlers


def _make_app() -> FastAPI:
    app = FastAPI()
    register_exception_handlers(app)

    @app.get("/http-401")
    async def http_401():
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Недействительный токен",
        )

    @app.get("/http-422-prefixed")
    async def http_422_prefixed():
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="unknown_column: q5.plan",
        )

    @app.get("/sql-error")
    async def sql_error():
        exc = SQLAlchemyError()
        exc.orig = Exception("budget_form #99 не существует")
        raise exc

    @app.get("/form/{form_id}")
    async def form_by_id(form_id: int):
        return {"form_id": form_id}

    return app


def test_http_exception_returns_structured_payload():
    client = TestClient(_make_app())
    response = client.get("/http-401")

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == {
        "code": status.HTTP_401_UNAUTHORIZED,
        "field": "",
        "message": "Недействительный токен",
    }


def test_http_validation_exception_extracts_field():
    client = TestClient(_make_app())
    response = client.get("/http-422-prefixed")

    assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
    assert response.json() == {
        "code": status.HTTP_422_UNPROCESSABLE_ENTITY,
        "field": "",
        "message": "unknown_column: q5.plan",
    }


def test_sqlalchemy_exception_returns_structured_payload():
    client = TestClient(_make_app())
    response = client.get("/sql-error")

    assert response.status_code == status.HTTP_404_NOT_FOUND
    assert response.json() == {
        "code": status.HTTP_404_NOT_FOUND,
        "field": "",
        "message": "budget_form #99 не существует",
    }


def test_request_validation_422_returns_structured_payload():
    client = TestClient(_make_app())
    response = client.get("/form/not-int")

    assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
    assert response.json() == {
        "code": status.HTTP_422_UNPROCESSABLE_ENTITY,
        "field": "form_id",
        "message": "Input should be a valid integer, unable to parse string as an integer",
    }
