from __future__ import annotations

from typing import Annotated
from typing import Optional
from unittest.mock import MagicMock

from pydantic.fields import Field

from amsdal_ml.mcp_server.server_model_explorer.services.crud_utils import extract_referenced_model_name
from amsdal_ml.mcp_server.server_model_explorer.services.crud_utils import get_action
from amsdal_ml.mcp_server.server_model_explorer.services.crud_utils import get_api_queryset
from amsdal_ml.mcp_server.server_model_explorer.services.crud_utils import get_property_source
from amsdal_ml.mcp_server.server_model_explorer.services.types import CrudOperation
from tests.fixtures.models.category import Category
from tests.fixtures.models.property_model import PropertyModel


def test_get_api_queryset_prefers_api_objects():
    mock_api_objects = MagicMock()
    mock_api_objects.all.return_value = 'api_queryset'
    mock_objects = MagicMock()
    mock_objects.all.return_value = 'default_queryset'

    mock_cls = MagicMock()
    mock_cls.api_objects = mock_api_objects
    mock_cls.objects = mock_objects

    result = get_api_queryset(mock_cls)

    assert result == 'api_queryset'


def test_get_api_queryset_falls_back_to_objects():
    mock_objects = MagicMock()
    mock_objects.all.return_value = 'default_queryset'

    mock_cls = MagicMock(spec=['objects'])
    mock_cls.objects = mock_objects

    result = get_api_queryset(mock_cls)

    assert result == 'default_queryset'


def test_get_action_maps_enum():
    action = get_action(CrudOperation.READ)
    assert action.value == 'read'


def test_extract_referenced_model_name_supports_optional():
    assert extract_referenced_model_name(Optional[Category]) == 'Category'


def test_extract_referenced_model_name_supports_annotated():
    annotation = Annotated[Category, Field(title='Category')]
    assert extract_referenced_model_name(annotation) == 'Category'


def test_extract_referenced_model_name_returns_none_for_non_model():
    assert extract_referenced_model_name(str) is None


def test_get_property_source_returns_source_for_property():
    source = get_property_source(PropertyModel, 'computed')

    assert source is not None
    assert 'def computed' in source


def test_get_property_source_returns_none_for_non_property():
    source = get_property_source(PropertyModel, 'missing')
    assert source is None
