"""Tests for G3 Temporal Resolution: superseded_by, is_active, conflict detection.

These tests use the real MemoryStorage with sqlite-vec. They verify
that supersede_memory correctly chains replacements and that default
searches hide superseded memories.
"""

from __future__ import annotations

from pathlib import Path

import pytest

from claude_engram.storage import MemoryStorage


@pytest.fixture()
def storage(tmp_path: Path) -> MemoryStorage:
    """Create a MemoryStorage with a temp database."""
    db = tmp_path / "test.db"
    s = MemoryStorage(db_path=db)
    yield s
    s.close()


class TestSupersedeMemory:
    """Core supersede_memory tests."""

    def test_supersede_hides_old_from_search(self, storage: MemoryStorage) -> None:
        """Store A, store B with supersedes=A.id, search should return B not A."""
        id_a = storage.store(
            content="We decided to use PostgreSQL for the main database",
            category="decision",
        )
        id_b = storage.store(
            content="We changed to SQLite for the main database instead of PostgreSQL",
            category="decision",
        )
        storage.supersede_memory(id_a, id_b)

        results = storage.search(query="main database decision")
        result_ids = [r["id"] for r in results]
        assert id_b in result_ids, "New decision should appear in search"
        assert id_a not in result_ids, "Superseded decision should be hidden"

    def test_supersede_sets_fields_correctly(self, storage: MemoryStorage) -> None:
        """supersede_memory should set superseded_by and is_active=0."""
        id_old = storage.store(content="old decision about caching", category="decision")
        id_new = storage.store(content="new decision about caching", category="decision")
        result = storage.supersede_memory(id_old, id_new)
        assert result is True

        conn = storage._get_conn()
        row = conn.execute(
            "SELECT superseded_by, is_active FROM memories WHERE id = ?",
            (id_old,),
        ).fetchone()
        assert row["superseded_by"] == id_new
        assert row["is_active"] == 0

    def test_supersede_nonexistent_returns_false(self, storage: MemoryStorage) -> None:
        """Superseding a non-existent memory should return False."""
        id_new = storage.store(content="new memory", category="decision")
        result = storage.supersede_memory(99999, id_new)
        assert result is False

    def test_supersede_chain(self, storage: MemoryStorage) -> None:
        """A -> B -> C chain: only C should appear in default search."""
        id_a = storage.store(content="API version 1 uses REST", category="decision")
        id_b = storage.store(content="API version 2 uses GraphQL", category="decision")
        id_c = storage.store(content="API version 3 uses gRPC", category="decision")

        storage.supersede_memory(id_a, id_b)
        storage.supersede_memory(id_b, id_c)

        results = storage.search(query="API version decision")
        result_ids = [r["id"] for r in results]
        assert id_c in result_ids
        assert id_b not in result_ids
        assert id_a not in result_ids


class TestIsActiveFilter:
    """Tests for include_inactive parameter."""

    def test_superseded_hidden_by_default(self, storage: MemoryStorage) -> None:
        """Superseded memories should not appear in default search."""
        id_old = storage.store(content="deprecated pattern for error handling", category="lesson")
        id_new = storage.store(content="improved pattern for error handling", category="lesson")
        storage.supersede_memory(id_old, id_new)

        results = storage.search(query="error handling pattern")
        assert all(r["is_active"] for r in results)

    def test_superseded_visible_with_include_inactive(self, storage: MemoryStorage) -> None:
        """Superseded memories should appear when include_inactive=True."""
        id_old = storage.store(content="old approach to authentication flow", category="decision")
        id_new = storage.store(content="new approach to authentication flow", category="decision")
        storage.supersede_memory(id_old, id_new)

        results = storage.search(
            query="authentication flow approach",
            include_inactive=True,
        )
        result_ids = [r["id"] for r in results]
        assert id_old in result_ids, "Inactive memory should be visible with include_inactive"
        assert id_new in result_ids

    def test_is_active_field_in_search_results(self, storage: MemoryStorage) -> None:
        """Search results should include is_active field."""
        storage.store(content="active memory about deployment", category="lesson")
        results = storage.search(query="deployment")
        assert len(results) > 0
        for r in results:
            assert "is_active" in r
            assert r["is_active"] is True

    def test_inactive_memory_shows_is_active_false(self, storage: MemoryStorage) -> None:
        """Inactive memories returned via include_inactive should have is_active=False."""
        id_old = storage.store(content="old logging strategy", category="decision")
        id_new = storage.store(content="new logging strategy", category="decision")
        storage.supersede_memory(id_old, id_new)

        results = storage.search(query="logging strategy", include_inactive=True)
        old_results = [r for r in results if r["id"] == id_old]
        assert len(old_results) == 1
        assert old_results[0]["is_active"] is False

    def test_get_recent_excludes_inactive_by_default(self, storage: MemoryStorage) -> None:
        """get_recent should also respect is_active filter."""
        id_old = storage.store(content="old recent memory", category="decision")
        id_new = storage.store(content="new recent memory", category="decision")
        storage.supersede_memory(id_old, id_new)

        results = storage.get_recent(limit=10)
        result_ids = [r["id"] for r in results]
        assert id_old not in result_ids


class TestMigrationV6:
    """Tests for v5->v6 migration adding temporal resolution columns."""

    def test_superseded_by_column_exists(self, storage: MemoryStorage) -> None:
        """memories table should have superseded_by column after migration."""
        conn = storage._get_conn()
        columns = conn.execute("PRAGMA table_info(memories)").fetchall()
        col_names = {c[1] for c in columns}
        assert "superseded_by" in col_names

    def test_is_active_column_exists(self, storage: MemoryStorage) -> None:
        """memories table should have is_active column after migration."""
        conn = storage._get_conn()
        columns = conn.execute("PRAGMA table_info(memories)").fetchall()
        col_names = {c[1] for c in columns}
        assert "is_active" in col_names

    def test_is_active_defaults_to_one(self, storage: MemoryStorage) -> None:
        """New memories should have is_active=1 by default."""
        mid = storage.store(content="fresh memory", category="lesson")
        conn = storage._get_conn()
        row = conn.execute("SELECT is_active FROM memories WHERE id = ?", (mid,)).fetchone()
        assert row["is_active"] == 1

    def test_superseded_by_defaults_to_null(self, storage: MemoryStorage) -> None:
        """New memories should have superseded_by=NULL by default."""
        mid = storage.store(content="not superseded memory", category="lesson")
        conn = storage._get_conn()
        row = conn.execute("SELECT superseded_by FROM memories WHERE id = ?", (mid,)).fetchone()
        assert row["superseded_by"] is None

    def test_schema_version_is_10(self, storage: MemoryStorage) -> None:
        """Schema version should be 10 after migration."""
        conn = storage._get_conn()
        version = conn.execute("PRAGMA user_version").fetchone()[0]
        assert version == 10

    def test_is_active_index_exists(self, storage: MemoryStorage) -> None:
        """idx_memories_is_active index should exist."""
        conn = storage._get_conn()
        indexes = conn.execute("PRAGMA index_list(memories)").fetchall()
        index_names = {idx[1] for idx in indexes}
        assert "idx_memories_is_active" in index_names
