"""Tests for Time-Travel Queries feature."""

from datetime import datetime, timedelta, timezone

import pytest

from locidb.core.db import LociDB
from locidb.core.node import MemoryNode


@pytest.fixture
def db(tmp_path):
    loci = LociDB(path=tmp_path / "test.loci")
    yield loci
    loci.close()


class TestSnapshot:
    def test_snapshot_empty_db(self, db):
        now = datetime.now(timezone.utc)
        assert db.snapshot(as_of=now) == []

    def test_snapshot_includes_current_nodes(self, db):
        db.memorize("Memory 1", entities=["test"])
        db.memorize("Memory 2", entities=["test"])
        future = datetime.now(timezone.utc) + timedelta(hours=1)
        nodes = db.snapshot(as_of=future)
        assert len(nodes) == 2

    def test_snapshot_excludes_future_nodes(self, db):
        past = datetime.now(timezone.utc) - timedelta(days=1)
        db.memorize("Memory created now", entities=["test"])
        nodes = db.snapshot(as_of=past)
        assert len(nodes) == 0

    def test_snapshot_includes_soft_deleted_if_deleted_after_cutoff(self, db):
        node = db.memorize("Will be deleted later", entities=["test"])
        import time; time.sleep(0.05)
        # Capture pre-delete timestamp BEFORE the deletion
        pre_delete = datetime.now(timezone.utc)
        import time; time.sleep(0.05)
        db.forget(node.id)  # soft delete happens AFTER pre_delete
        # Snapshot at pre_delete should still see the node
        nodes = db.snapshot(as_of=pre_delete)
        assert any(n.id == node.id for n in nodes)

    def test_snapshot_scope_filter(self, db):
        db.memorize("Project A memory", entities=["a"], scope="project:a")
        db.memorize("Project B memory", entities=["b"], scope="project:b")
        future = datetime.now(timezone.utc) + timedelta(hours=1)
        nodes = db.snapshot(as_of=future, scope="project:a")
        assert len(nodes) == 1
        assert nodes[0].context_scope == "project:a"


class TestTimeline:
    def test_timeline_chronological(self, db):
        db.memorize("First", entities=["test"])
        db.memorize("Second", entities=["test"])
        db.memorize("Third", entities=["test"])
        nodes = db.timeline()
        # Should be in chronological order
        for i in range(len(nodes) - 1):
            assert nodes[i].timestamp <= nodes[i + 1].timestamp

    def test_timeline_entity_filter(self, db):
        db.memorize("Python stuff", entities=["python"])
        db.memorize("Java stuff", entities=["java"])
        db.memorize("More Python", entities=["python"])
        nodes = db.timeline(entity="python")
        assert len(nodes) == 2
        assert all("python" in n.entity_tags for n in nodes)

    def test_timeline_includes_deleted(self, db):
        node = db.memorize("To be forgotten", entities=["test"])
        db.memorize("Still here", entities=["test"])
        db.forget(node.id)
        nodes = db.timeline()
        assert len(nodes) == 2  # includes deleted


class TestDiff:
    def test_diff_shows_added(self, db):
        t1 = datetime.now(timezone.utc) - timedelta(seconds=1)
        db.memorize("New memory", entities=["test"])
        t2 = datetime.now(timezone.utc) + timedelta(seconds=1)
        result = db.diff(t1, t2)
        assert len(result["added"]) == 1
        assert result["t1_count"] == 0
        assert result["t2_count"] == 1

    def test_diff_shows_removed(self, db):
        node = db.memorize("Will forget", entities=["test"])
        import time; time.sleep(0.05)
        t1 = datetime.now(timezone.utc)
        import time; time.sleep(0.05)
        db.forget(node.id)
        import time; time.sleep(0.05)
        t2 = datetime.now(timezone.utc)
        result = db.diff(t1, t2)
        assert len(result["removed"]) == 1

    def test_diff_empty(self, db):
        t1 = datetime.now(timezone.utc)
        t2 = datetime.now(timezone.utc) + timedelta(hours=1)
        result = db.diff(t1, t2)
        assert result["added"] == []
        assert result["removed"] == []


class TestRecallAsOf:
    def test_recall_with_as_of(self, db):
        past = datetime.now(timezone.utc) - timedelta(days=1)
        db.memorize("Created now", entities=["test"])
        # Recall as of yesterday should find nothing (memory was just created)
        results = db.recall("test", as_of=past)
        assert len(results) == 0

    def test_recall_without_as_of(self, db):
        db.memorize("Current memory", entities=["test"])
        results = db.recall("current memory")
        assert len(results) >= 1
