"""Tests for DomainModel."""
from __future__ import annotations

from datetime import datetime

import pytest
from pydantic import ValidationError as PydanticValidationError

from repo_core import DomainModel


class Article(DomainModel):
    id: int
    title: str
    body: str = ""
    published: bool = False


class ArticleWithDate(DomainModel):
    id: int
    title: str
    created_at: datetime | None = None


# ---------------------------------------------------------------------------

def test_from_db_creates_instance():
    article = Article.from_db({"id": 1, "title": "Hello", "body": "World"})
    assert article.id == 1
    assert article.title == "Hello"
    assert article.body == "World"


def test_from_db_applies_defaults():
    article = Article.from_db({"id": 2, "title": "Test"})
    assert article.body == ""
    assert article.published is False


def test_to_db_returns_full_dict():
    article = Article(id=1, title="Hello", body="World", published=True)
    row = article.to_db()
    assert row == {"id": 1, "title": "Hello", "body": "World", "published": True}


def test_to_db_partial_returns_only_set_fields():
    article = Article.model_construct(id=1, title="Updated")
    row = article.to_db_partial()
    assert "id" in row
    assert "title" in row


def test_model_validates_types():
    with pytest.raises(PydanticValidationError):
        Article.from_db({"id": "not-an-int", "title": "Hello"})


def test_from_db_with_orm_like_object():
    class FakeORM:
        id = 10
        title = "ORM title"
        body = "body text"
        published = False

    article = Article.model_validate(FakeORM(), from_attributes=True)
    assert article.id == 10
    assert article.title == "ORM title"


def test_model_equality():
    a = Article(id=1, title="A", body="", published=False)
    b = Article(id=1, title="A", body="", published=False)
    assert a == b


def test_model_serialise_to_json():
    article = Article(id=1, title="Hello", body="World", published=False)
    json_str = article.model_dump_json()
    assert '"title":"Hello"' in json_str or '"title": "Hello"' in json_str
