"""
Simple tests for EvolveClient wrapper interface.
"""

import datetime
import importlib
from pathlib import Path

import pytest

from altk_evolve.backend.base import BaseEntityBackend
from altk_evolve.config.evolve import EvolveConfig
from altk_evolve.schema.core import Entity, Namespace, RecordedEntity
from altk_evolve.schema.conflict_resolution import EntityUpdate
from altk_evolve.schema.exceptions import NamespaceNotFoundException, NamespaceAlreadyExistsException
from altk_evolve.frontend.client.evolve_client import EvolveClient


@pytest.fixture(scope="module")
def evolve_client() -> EvolveClient:
    config = EvolveConfig(backend="filesystem")
    evolve_client = EvolveClient(config=config)
    return evolve_client


@pytest.mark.unit
def test_evolve_config_reads_backend_from_dotenv(tmp_path, monkeypatch):
    env_path = tmp_path / ".env"
    env_path.write_text("EVOLVE_BACKEND=postgres\n", encoding="utf-8")

    original_cwd = Path.cwd()
    monkeypatch.chdir(tmp_path)
    monkeypatch.delenv("EVOLVE_BACKEND", raising=False)

    import altk_evolve.config.evolve as evolve_module

    original_backend = evolve_module.evolve_config.backend
    reloaded_module = importlib.reload(evolve_module)

    try:
        assert reloaded_module.EvolveConfig().backend == "postgres"
        assert reloaded_module.evolve_config.backend == "postgres"
    finally:
        monkeypatch.chdir(original_cwd)
        monkeypatch.delenv("EVOLVE_BACKEND", raising=False)
        reloaded_module.evolve_config.backend = original_backend
        importlib.reload(reloaded_module)
        reloaded_module.evolve_config.backend = original_backend


@pytest.mark.unit
def test_health_check(evolve_client: EvolveClient, monkeypatch):
    # Client should return False derived from API response
    def never_ready(self) -> bool:
        return False

    monkeypatch.setattr(evolve_client.backend, "ready", never_ready.__get__(evolve_client, BaseEntityBackend))
    health_status = evolve_client.ready()
    assert not health_status

    # Client should return True derived from API response
    def always_ready(self) -> bool:
        return True

    monkeypatch.setattr(evolve_client.backend, "ready", always_ready.__get__(evolve_client, BaseEntityBackend))
    health_status = evolve_client.ready()
    assert health_status


@pytest.mark.unit
def test_create_namespace(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `Namespace` object derived from API response
    created_at = datetime.datetime.now(datetime.UTC)

    def create_namespace(self, namespace_id=None) -> Namespace:
        return Namespace(id="foobar", created_at=created_at)

    monkeypatch.setattr(evolve_client.backend, "create_namespace", create_namespace.__get__(evolve_client.backend, BaseEntityBackend))
    result = evolve_client.create_namespace(namespace_id="foobar")
    assert result.id == "foobar"
    assert result.created_at == created_at


@pytest.mark.unit
def test_create_namespace_already_exists(evolve_client: EvolveClient, monkeypatch):
    # Client should raise an exception
    def create_namespace(self, namespace_id=None) -> Namespace:
        raise NamespaceAlreadyExistsException()

    monkeypatch.setattr(evolve_client.backend, "create_namespace", create_namespace.__get__(evolve_client.backend, BaseEntityBackend))
    with pytest.raises(NamespaceAlreadyExistsException):
        evolve_client.create_namespace(namespace_id="foobar")


@pytest.mark.unit
def test_get_namespace_details(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `Namespace` object derived from API response
    created_at = datetime.datetime.now(datetime.UTC)

    def get_namespace_details(self, namespace_id=None) -> Namespace:
        return Namespace(id="foobar", created_at=created_at)

    monkeypatch.setattr(
        evolve_client.backend, "get_namespace_details", get_namespace_details.__get__(evolve_client.backend, BaseEntityBackend)
    )
    result = evolve_client.get_namespace_details(namespace_id="foobar")
    assert result.id == "foobar"
    assert result.created_at == created_at


@pytest.mark.unit
def test_get_namespace_details_nonexistent(evolve_client: EvolveClient, monkeypatch):
    # Client should raise an exception
    def get_namespace_details(self, namespace_id=None) -> Namespace:
        raise NamespaceNotFoundException()

    monkeypatch.setattr(
        evolve_client.backend, "get_namespace_details", get_namespace_details.__get__(evolve_client.backend, BaseEntityBackend)
    )
    with pytest.raises(NamespaceNotFoundException):
        evolve_client.get_namespace_details(namespace_id="foobar")


@pytest.mark.unit
def test_search_namespaces(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `Namespace` list derived from API response
    created_at = datetime.datetime.now(datetime.UTC)

    def search_namespaces(self, limit=10) -> list[Namespace]:
        return [Namespace(id="foobar", created_at=created_at)]

    monkeypatch.setattr(evolve_client.backend, "search_namespaces", search_namespaces.__get__(evolve_client.backend, BaseEntityBackend))
    result = evolve_client.search_namespaces()
    assert result[0].id == "foobar"
    assert result[0].created_at == created_at


@pytest.mark.unit
def test_delete_namespace(evolve_client: EvolveClient, monkeypatch):
    # Function should successfully be called in backend; essentially a no-op test.
    def delete_namespace(self, namespace_id):
        pass

    monkeypatch.setattr(evolve_client.backend, "delete_namespace", delete_namespace.__get__(evolve_client.backend, BaseEntityBackend))
    evolve_client.delete_namespace(namespace_id="foobar")


@pytest.mark.unit
def test_update_entities(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `EntityUpdate` list derived from API response
    def update_entities(self, namespace_id, entity, enable_conflict_resolution=True) -> list[EntityUpdate]:
        return [EntityUpdate(id="1", type="fact", content="User's name is Foobar", event="ADD")]

    monkeypatch.setattr(evolve_client.backend, "update_entities", update_entities.__get__(evolve_client.backend, BaseEntityBackend))
    result = evolve_client.update_entities(namespace_id="foobar", entities=[Entity(type="fact", content="User's name is Foobar.")])
    assert result[0].id == "1"
    assert result[0].content == "User's name is Foobar"
    assert result[0].event == "ADD"


@pytest.mark.unit
def test_search_entities(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `RecordedEntity` list derived from API response
    created_at = datetime.datetime.now(datetime.UTC)

    def search_entities(self, namespace_id, query, filters, limit=10) -> list[RecordedEntity]:
        return [RecordedEntity(id="1", type="fact", created_at=created_at, content="User's name is Foobar.")]

    monkeypatch.setattr(evolve_client.backend, "search_entities", search_entities.__get__(evolve_client.backend, BaseEntityBackend))
    result = evolve_client.search_entities(namespace_id="foobar", query="name")
    assert result[0].id == "1"
    assert result[0].content == "User's name is Foobar."
    assert result[0].created_at == created_at


@pytest.mark.unit
def test_get_all_entities(evolve_client: EvolveClient, monkeypatch):
    # Client should return a valid `RecordedEntity` list derived from API response
    created_at = datetime.datetime.now(datetime.UTC)

    def search_entities(self, namespace_id, query, filters, limit=10) -> list[RecordedEntity]:
        return [RecordedEntity(id="1", type="fact", created_at=created_at, content="User's name is Foobar.")]

    monkeypatch.setattr(evolve_client.backend, "search_entities", search_entities.__get__(evolve_client.backend, BaseEntityBackend))
    result = evolve_client.search_entities(namespace_id="foobar", query="name")
    assert result[0].id == "1"
    assert result[0].content == "User's name is Foobar."
    assert result[0].created_at == created_at


@pytest.mark.unit
def test_delete_entity(evolve_client: EvolveClient, monkeypatch):
    # Function should successfully be called in backend; essentially a no-op test.
    def delete_entity_by_id(self, namespace_id, entity_id):
        pass

    monkeypatch.setattr(evolve_client.backend, "delete_entity_by_id", delete_entity_by_id.__get__(evolve_client.backend, BaseEntityBackend))
    evolve_client.delete_entity_by_id(namespace_id="foobar", entity_id="1")
