"""Tests for graph retrieval — BFS 2-hop traversal and scoring."""

from __future__ import annotations

import uuid
from dataclasses import dataclass
from datetime import UTC, datetime

from conftest import run_async

from arandu.read.graph_retrieval import (
    GraphRetrievalResult,
    _display_name_from_key,
    _entity_name_in_query,
    retrieve_graph_facts,
)


# ---------------------------------------------------------------------------
# Fake MemoryFact for graph scoring tests
# ---------------------------------------------------------------------------
@dataclass
class FakeGraphFact:
    """Minimal MemoryFact-like object for graph retrieval tests."""

    id: uuid.UUID | None = None
    user_id: str = "user_123"
    entity_type: str = "person"
    entity_key: str = "person:kevin"
    entity_name: str = "Kevin"
    attribute_key: str = "preference"
    value_text: str = "likes coffee"
    value_json: str | None = None
    fact_text: str = "Kevin likes coffee"
    confidence: float = 0.9
    importance: float = 0.5
    valid_from: datetime | None = None
    valid_to: datetime | None = None
    embedding: list[float] | None = None

    def __post_init__(self) -> None:
        if self.id is None:
            self.id = uuid.uuid4()
        if self.valid_from is None:
            self.valid_from = datetime.now(UTC)


# ===========================================================================
# Test: display name derivation
# ===========================================================================


class TestDisplayNameFromKey:
    def test_user_self_returns_user(self) -> None:
        assert _display_name_from_key("user:self") == "User"

    def test_person_key_returns_title_case(self) -> None:
        assert _display_name_from_key("person:kevin_nascimento") == "Kevin Nascimento"

    def test_org_key_returns_title_case(self) -> None:
        assert _display_name_from_key("org:acme_corp") == "Acme Corp"

    def test_no_prefix_returns_title_case(self) -> None:
        assert _display_name_from_key("some_entity") == "Some Entity"


# ===========================================================================
# Test: entity name in query
# ===========================================================================


class TestEntityNameInQuery:
    def test_name_found_in_query(self) -> None:
        fact = FakeGraphFact(entity_name="Kevin")
        assert _entity_name_in_query(fact, "como está o Kevin?") is True

    def test_name_not_found_in_query(self) -> None:
        fact = FakeGraphFact(entity_name="Kevin")
        assert _entity_name_in_query(fact, "como está o Pedro?") is False

    def test_case_insensitive(self) -> None:
        fact = FakeGraphFact(entity_name="Kevin")
        assert _entity_name_in_query(fact, "KEVIN é meu amigo") is True

    def test_no_entity_name(self) -> None:
        fact = FakeGraphFact(entity_name="")
        assert _entity_name_in_query(fact, "qualquer coisa") is False

    def test_none_entity_name(self) -> None:
        fact = FakeGraphFact()
        fact.entity_name = None  # type: ignore[assignment]
        assert _entity_name_in_query(fact, "qualquer coisa") is False


# ===========================================================================
# Test: empty input returns empty result
# ===========================================================================


class TestRetrieveGraphFactsEmpty:
    def test_empty_entity_keys_returns_empty(self) -> None:
        from unittest.mock import AsyncMock

        session = AsyncMock()
        result = run_async(retrieve_graph_facts(session, "user_123", []))

        assert isinstance(result, GraphRetrievalResult)
        assert result.facts == []
        assert result.neighbor_keys == []
        assert result.edges_traversed == 0
