"""Tests for lapis_spec.type_mapper."""

import pytest

from lapis_spec.type_mapper import format_default_value, map_type, map_type_with_nullable


class TestMapType:
    @pytest.mark.parametrize(
        "schema, expected",
        [
            ({"type": "string"}, "str"),
            ({"type": "string", "format": "date"}, "date"),
            ({"type": "string", "format": "date-time"}, "datetime"),
            ({"type": "string", "format": "binary"}, "file"),
            ({"type": "string", "format": "email"}, "str"),
            ({"type": "string", "format": "uuid"}, "str"),
            ({"type": "string", "format": "uri"}, "str"),
            ({"type": "string", "format": "password"}, "str"),
            ({"type": "integer"}, "int"),
            ({"type": "integer", "format": "int32"}, "int"),
            ({"type": "integer", "format": "int64"}, "int"),
            ({"type": "number"}, "float"),
            ({"type": "number", "format": "float"}, "float"),
            ({"type": "number", "format": "double"}, "float"),
            ({"type": "boolean"}, "bool"),
        ],
    )
    def test_scalar_types(self, schema, expected):
        assert map_type(schema) == expected

    def test_array(self):
        schema = {"type": "array", "items": {"type": "string"}}
        assert map_type(schema) == "[str]"

    def test_nested_array(self):
        schema = {
            "type": "array",
            "items": {"type": "array", "items": {"type": "integer"}},
        }
        assert map_type(schema) == "[[int]]"

    def test_object_with_additional_properties(self):
        schema = {
            "type": "object",
            "additionalProperties": {"type": "string"},
        }
        assert map_type(schema) == "{str:str}"

    def test_object_with_additional_properties_true(self):
        schema = {"type": "object", "additionalProperties": True}
        assert map_type(schema) == "{str:any}"

    def test_object_without_properties(self):
        schema = {"type": "object"}
        assert map_type(schema) == "any"

    def test_object_with_properties(self):
        schema = {
            "type": "object",
            "required": ["name"],
            "properties": {
                "name": {"type": "string"},
                "age": {"type": "integer"},
            },
        }
        result = map_type(schema)
        assert "name: str" in result
        assert "age?" in result or "age: int" in result

    def test_enum(self):
        schema = {"type": "string", "enum": ["a", "b", "c"]}
        assert map_type(schema) == "a | b | c"

    def test_empty_schema(self):
        assert map_type({}) == "any"

    def test_none_schema(self):
        assert map_type(None) == "any"

    def test_unknown_format_falls_back(self):
        schema = {"type": "string", "format": "unknown-custom"}
        assert map_type(schema) == "str"

    def test_openapi_31_type_array(self):
        schema = {"type": ["string", "null"]}
        assert map_type(schema) == "str"


class TestMapTypeWithNullable:
    def test_nullable_30(self):
        schema = {"type": "string", "nullable": True}
        assert map_type_with_nullable(schema) == "str?"

    def test_nullable_31(self):
        schema = {"type": ["string", "null"]}
        assert map_type_with_nullable(schema) == "str?"

    def test_not_nullable(self):
        schema = {"type": "string"}
        assert map_type_with_nullable(schema) == "str"


class TestFormatDefaultValue:
    def test_none(self):
        assert format_default_value(None) is None

    def test_string(self):
        assert format_default_value("US") == '"US"'

    def test_integer(self):
        assert format_default_value(20) == "20"

    def test_bool_true(self):
        assert format_default_value(True) == "true"

    def test_bool_false(self):
        assert format_default_value(False) == "false"

    def test_float(self):
        assert format_default_value(3.14) == "3.14"
