"""Tests for BaseRepository model-conversion helpers
(_from_db, _from_db_many, _from_search, _from_search_many,
_from_warehouse, _from_warehouse_many)."""

from __future__ import annotations

import pytest

from repo_core import BaseRepository, DomainModel


# ---------------------------------------------------------------------------
# Test model
# ---------------------------------------------------------------------------

class Person(DomainModel):
    id: int
    name: str
    email: str = ""

    _db_include = {"id", "name", "email"}
    _search_include = {"id", "name"}
    _warehouse_include = None


class ConversionRepo(BaseRepository[Person]):
    _backends = set()


# ===========================================================================
# _from_db / _from_db_many
# ===========================================================================

def test_from_db_returns_model_when_model_set():
    repo = ConversionRepo(model=Person)
    result = repo._from_db({"id": 1, "name": "Alice", "email": "a@b.com"})
    assert isinstance(result, Person)
    assert result.id == 1
    assert result.name == "Alice"


def test_from_db_returns_raw_dict_when_model_none():
    repo = ConversionRepo(model=None)
    result = repo._from_db({"id": 1, "name": "Alice"})
    assert result == {"id": 1, "name": "Alice"}


def test_from_db_returns_none_when_row_is_none():
    repo = ConversionRepo(model=Person)
    result = repo._from_db(None)
    assert result is None


def test_from_db_returns_none_when_row_none_and_model_none():
    repo = ConversionRepo(model=None)
    result = repo._from_db(None)
    assert result is None


def test_from_db_many_returns_models():
    repo = ConversionRepo(model=Person)
    rows = [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}]
    result = repo._from_db_many(rows)
    assert len(result) == 2
    assert all(isinstance(r, Person) for r in result)
    assert result[0].name == "A"
    assert result[1].name == "B"


def test_from_db_many_returns_raw_dicts_when_model_none():
    repo = ConversionRepo(model=None)
    rows = [{"id": 1}, {"id": 2}]
    result = repo._from_db_many(rows)
    assert result == rows


def test_from_db_many_empty_list():
    repo = ConversionRepo(model=Person)
    assert repo._from_db_many([]) == []


# ===========================================================================
# _from_search / _from_search_many
# ===========================================================================

def test_from_search_returns_model():
    """from_search uses model_validate — pass a flat dict matching model fields."""
    repo = ConversionRepo(model=Person)
    result = repo._from_search({"id": 5, "name": "Search", "email": "s@b.com"})
    assert isinstance(result, Person)
    assert result.id == 5
    assert result.name == "Search"


def test_from_search_returns_raw_dict_when_model_none():
    repo = ConversionRepo(model=None)
    doc = {"id": 1, "name": "X"}
    assert repo._from_search(doc) == doc


def test_from_search_returns_none_when_row_is_none():
    repo = ConversionRepo(model=Person)
    assert repo._from_search(None) is None


def test_from_search_many_returns_models():
    repo = ConversionRepo(model=Person)
    rows = [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}]
    result = repo._from_search_many(rows)
    assert len(result) == 2
    assert all(isinstance(r, Person) for r in result)


def test_from_search_many_returns_raw_when_model_none():
    repo = ConversionRepo(model=None)
    rows = [{"id": 1}, {"id": 2}]
    assert repo._from_search_many(rows) == rows


def test_from_search_many_empty_list():
    repo = ConversionRepo(model=Person)
    assert repo._from_search_many([]) == []


# ===========================================================================
# _from_warehouse / _from_warehouse_many
# ===========================================================================

def test_from_warehouse_returns_model():
    repo = ConversionRepo(model=Person)
    result = repo._from_warehouse({"id": 10, "name": "WH", "email": "wh@b.com"})
    assert isinstance(result, Person)
    assert result.id == 10


def test_from_warehouse_returns_raw_dict_when_model_none():
    repo = ConversionRepo(model=None)
    assert repo._from_warehouse({"id": 1}) == {"id": 1}


def test_from_warehouse_returns_none_when_row_is_none():
    repo = ConversionRepo(model=Person)
    assert repo._from_warehouse(None) is None


def test_from_warehouse_many_returns_models():
    repo = ConversionRepo(model=Person)
    rows = [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}]
    result = repo._from_warehouse_many(rows)
    assert len(result) == 2
    assert all(isinstance(r, Person) for r in result)


def test_from_warehouse_many_returns_raw_when_model_none():
    repo = ConversionRepo(model=None)
    rows = [{"id": 1}, {"id": 2}]
    assert repo._from_warehouse_many(rows) == rows


def test_from_warehouse_many_empty_list():
    repo = ConversionRepo(model=Person)
    assert repo._from_warehouse_many([]) == []
