"""Tests for allOf handling at requestBody top level."""

from fastmcp.experimental.utilities.openapi.models import (
    HTTPRoute,
    RequestBodyInfo,
)
from fastmcp.experimental.utilities.openapi.schemas import _combine_schemas


def test_allof_at_requestbody_top_level():
    """Test that allOf schemas at requestBody top level are properly merged."""

    # Create a route with allOf at the requestBody top level
    route = HTTPRoute(
        path="/test",
        method="POST",
        operation_id="testOperation",
        parameters=[],
        request_body=RequestBodyInfo(
            required=True,
            content_schema={
                "application/json": {
                    "allOf": [
                        {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string"},
                                "age": {"type": "integer"},
                            },
                            "required": ["name"],
                        },
                        {
                            "type": "object",
                            "properties": {
                                "email": {"type": "string"},
                                "phone": {"type": "string"},
                            },
                            "required": ["email"],
                        },
                    ]
                }
            },
        ),
        responses={},
    )

    # Combine schemas - this should merge allOf schemas
    combined = _combine_schemas(route)

    # Check that all properties from both allOf schemas are present
    properties = combined.get("properties", {})
    assert "name" in properties
    assert "age" in properties
    assert "email" in properties
    assert "phone" in properties

    # Check property types
    assert properties["name"]["type"] == "string"
    assert properties["age"]["type"] == "integer"
    assert properties["email"]["type"] == "string"
    assert properties["phone"]["type"] == "string"

    # Check that required fields are merged correctly
    required = set(combined.get("required", []))
    assert "name" in required
    assert "email" in required

    # allOf should be removed after merging
    assert "allOf" not in combined


def test_allof_with_nested_properties():
    """Test allOf with nested object properties."""

    route = HTTPRoute(
        path="/test",
        method="POST",
        operation_id="testNested",
        parameters=[],
        request_body=RequestBodyInfo(
            required=True,
            content_schema={
                "application/json": {
                    "allOf": [
                        {
                            "type": "object",
                            "properties": {
                                "user": {
                                    "type": "object",
                                    "properties": {
                                        "id": {"type": "integer"},
                                        "name": {"type": "string"},
                                    },
                                }
                            },
                            "required": ["user"],
                        },
                        {
                            "type": "object",
                            "properties": {
                                "metadata": {
                                    "type": "object",
                                    "properties": {
                                        "created": {"type": "string"},
                                        "updated": {"type": "string"},
                                    },
                                }
                            },
                        },
                    ]
                }
            },
        ),
        responses={},
    )

    combined = _combine_schemas(route)

    # Check nested properties are preserved
    properties = combined.get("properties", {})
    assert "user" in properties
    assert "metadata" in properties

    # Check nested structure
    assert properties["user"]["type"] == "object"
    assert "id" in properties["user"]["properties"]
    assert "name" in properties["user"]["properties"]

    assert properties["metadata"]["type"] == "object"
    assert "created" in properties["metadata"]["properties"]
    assert "updated" in properties["metadata"]["properties"]

    # Check required
    required = set(combined.get("required", []))
    assert "user" in required
    assert "metadata" not in required  # Not in any required array


def test_allof_with_overlapping_properties():
    """Test allOf with overlapping property names (later schemas override)."""

    route = HTTPRoute(
        path="/test",
        method="POST",
        operation_id="testOverlap",
        parameters=[],
        request_body=RequestBodyInfo(
            required=True,
            content_schema={
                "application/json": {
                    "allOf": [
                        {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string", "minLength": 1},
                                "age": {"type": "integer"},
                            },
                            "required": ["name"],
                        },
                        {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string", "maxLength": 50},  # Override
                                "email": {"type": "string"},
                            },
                            "required": ["email"],
                        },
                    ]
                }
            },
        ),
        responses={},
    )

    combined = _combine_schemas(route)

    properties = combined.get("properties", {})

    # Later schema should win for overlapping properties
    assert "name" in properties
    assert properties["name"]["type"] == "string"
    assert "maxLength" in properties["name"]  # From second schema
    assert properties["name"]["maxLength"] == 50

    # Check other properties
    assert "age" in properties
    assert "email" in properties

    # Both name and email should be required
    required = set(combined.get("required", []))
    assert "name" in required
    assert "email" in required


def test_no_allof_passthrough():
    """Test that schemas without allOf pass through unchanged."""

    route = HTTPRoute(
        path="/test",
        method="POST",
        operation_id="testNoAllOf",
        parameters=[],
        request_body=RequestBodyInfo(
            required=True,
            content_schema={
                "application/json": {
                    "type": "object",
                    "properties": {"simple": {"type": "string"}},
                    "required": ["simple"],
                }
            },
        ),
        responses={},
    )

    combined = _combine_schemas(route)

    # Should pass through unchanged
    properties = combined.get("properties", {})
    assert "simple" in properties
    assert properties["simple"]["type"] == "string"

    required = set(combined.get("required", []))
    assert "simple" in required

    # No allOf in original or result
    assert "allOf" not in combined
