from __future__ import annotations

import pytest

from django_anyllm.serializers import deserialize_data, serialize_instance

from .models import Author, Book


class TestSerializeInstance:
    """Tests for serialize_instance."""

    def test_basic_fields(self, db):
        author = Author.objects.create(
            name="Jane Doe",
            email="jane@example.com",
            is_active=True,
        )
        data = serialize_instance(author)
        assert data["name"] == "Jane Doe"
        assert data["email"] == "jane@example.com"
        assert data["is_active"] is True
        assert data["bio"] == ""
        assert data["pk"] == author.pk

    def test_datetime_format(self, db):
        author = Author.objects.create(name="Test", email="t@example.com")
        data = serialize_instance(author)
        assert data["created_at"].endswith("+00:00")

    def test_foreign_key_by_pk(self, db):
        author = Author.objects.create(name="Author", email="a@example.com")
        book = Book.objects.create(title="Test Book", author=author)
        data = serialize_instance(book)
        assert data["author"] == author.pk

    def test_foreign_key_with_depth(self, db):
        author = Author.objects.create(name="Author", email="a@example.com")
        book = Book.objects.create(title="Test Book", author=author)
        data = serialize_instance(book, depth=1)
        assert data["author"]["name"] == "Author"

    def test_choices_field(self, db):
        author = Author.objects.create(name="Author", email="a@example.com")
        book = Book.objects.create(
            title="Test Book", author=author, genre=Book.Genre.SCIENCE
        )
        data = serialize_instance(book)
        assert data["genre"]["value"] == "science"
        assert data["genre"]["display"] == "Science"


class TestDeserializeData:
    """Tests for deserialize_data."""

    def test_valid_fields(self):
        data = deserialize_data(Author, {"name": "John", "email": "john@example.com"})
        assert data == {"name": "John", "email": "john@example.com"}

    def test_strips_read_only(self):
        data = deserialize_data(Author, {"name": "John", "created_at": "2024-01-01"})
        assert "created_at" not in data

    def test_rejects_unknown_field(self):
        with pytest.raises(ValueError, match="Unknown field 'nope'"):
            deserialize_data(Author, {"nope": "value"})
