import json

import pytest
from pydantic import BaseModel, ValidationError

from iisi_app_core import ConflictError, DefaultApiExceptionMapper, DomainValidationError, FeatureDisabledError


class InvalidPayload(BaseModel):
    count: int


def _json_body(response):  # noqa: ANN001, ANN202
    return json.loads(response["body"])


def test_default_api_exception_mapper_returns_422_for_pydantic_validation_errors() -> None:
    mapper = DefaultApiExceptionMapper()

    with pytest.raises(ValidationError) as exc_info:
        InvalidPayload.model_validate({"count": "not-a-number"})

    response = mapper.map_exception(exc_info.value)
    body = _json_body(response)

    assert response["statusCode"] == 422
    assert body["code"] == "VALIDATION_ERROR"
    assert body["message"] == "Invalid input"
    assert body["details"][0]["loc"] == ["count"]


def test_default_api_exception_mapper_returns_422_for_domain_validation_errors() -> None:
    mapper = DefaultApiExceptionMapper()

    response = mapper.map_exception(DomainValidationError("tenant_id must be a string"))
    body = _json_body(response)

    assert response["statusCode"] == 422
    assert body["code"] == "VALIDATION_ERROR"
    assert body["message"] == "Invalid input"
    assert body["details"] == ["tenant_id must be a string"]


def test_default_api_exception_mapper_returns_409_for_conflicts() -> None:
    mapper = DefaultApiExceptionMapper()

    response = mapper.map_exception(
        ConflictError(
            "User already exists",
            error_code="USER_ALREADY_EXISTS",
            details=[{"field": "email"}],
        )
    )
    body = _json_body(response)

    assert response["statusCode"] == 409
    assert body["code"] == "USER_ALREADY_EXISTS"
    assert body["message"] == "User already exists"
    assert body["details"] == [{"field": "email"}]


def test_default_api_exception_mapper_returns_403_for_feature_disabled_errors() -> None:
    mapper = DefaultApiExceptionMapper()

    response = mapper.map_exception(FeatureDisabledError("Feature disabled: /feature/auth/register_user/enabled"))
    body = _json_body(response)

    assert response["statusCode"] == 403
    assert body["code"] == "FEATURE_DISABLED"
    assert body["message"] == "Feature disabled"
    assert body["details"] == ["Feature disabled: /feature/auth/register_user/enabled"]
