from __future__ import annotations

import pytest

from django_anyllm.registry import ModelRegistry
from django_anyllm.tools.introspection import (
    describe_model,
    get_model_schema,
    list_registered_models,
)


class TestListRegisteredModels:
    """Tests for list_registered_models."""

    def test_returns_all_registered(self, registry):
        models = list_registered_models(registry)
        assert len(models) == 2

    def test_includes_docstring(self, registry):
        models = list_registered_models(registry)
        author = next(m for m in models if m["model_name"] == "author")
        assert author["docstring"] == "A writer of books."


class TestDescribeModel:
    """Tests for describe_model."""

    def test_basic_structure(self, registry):
        info = describe_model(registry, "tests", "author")
        assert info["app_label"] == "tests"
        assert info["model_name"] == "author"
        assert info["verbose_name"] == "author"
        assert info["docstring"] == "A writer of books."

    def test_includes_help_text(self, registry):
        info = describe_model(registry, "tests", "author")
        name_field = next(f for f in info["fields"] if f["name"] == "name")
        assert name_field["help_text"] == "The author's full name."

    def test_includes_verbose_name(self, registry):
        info = describe_model(registry, "tests", "author")
        name_field = next(f for f in info["fields"] if f["name"] == "name")
        assert name_field["verbose_name"] == "name"

    def test_includes_choices(self, registry):
        info = describe_model(registry, "tests", "book")
        genre_field = next(f for f in info["fields"] if f["name"] == "genre")
        assert "choices" in genre_field
        values = {c["value"] for c in genre_field["choices"]}
        assert values == {"fiction", "non_fiction", "science"}

    def test_relationships(self, registry):
        # Forward FKs are concrete fields.
        book_info = describe_model(registry, "tests", "book")
        author_field = next(f for f in book_info["fields"] if f["name"] == "author")
        assert author_field["relationship"]["type"] == "ForeignKey"
        assert author_field["relationship"]["to"] == "tests.Author"

        # Reverse relations appear on the related model.
        author_info = describe_model(registry, "tests", "author")
        books_rel = next(
            r for r in author_info["relationships"] if r["name"] == "books"
        )
        assert books_rel["relationship"]["type"] == "ManyToOneRel"

    def test_unregistered_model(self):
        reg = ModelRegistry()
        with pytest.raises(Exception):
            describe_model(reg, "tests", "author")


class TestGetModelSchema:
    """Tests for get_model_schema."""

    def test_schema_structure(self, registry):
        schema = get_model_schema(registry, "tests", "author")
        assert schema["type"] == "object"
        assert schema["title"] == "author"
        assert "properties" in schema
        assert "name" in schema["properties"]

    def test_field_descriptions(self, registry):
        schema = get_model_schema(registry, "tests", "author")
        name_prop = schema["properties"]["name"]
        assert "description" in name_prop
        assert "The author's full name." in name_prop["description"]

    def test_required_fields(self, registry):
        schema = get_model_schema(registry, "tests", "author")
        assert "name" in schema["required"]
        assert "email" in schema["required"]
        assert "created_at" not in schema["required"]
