"""Tests for confidence-based adaptive recall.

When the query pipeline returns low-confidence results (avg top-3 relevance < 0.3),
it automatically retries with relaxed parameters. Confidence is surfaced to callers
via result metadata and bridge output.
"""
import os
import pytest
from unittest.mock import patch

from omega.sqlite_store import SQLiteStore
from omega.sqlite_store._query import ADAPTIVE_RETRY_THRESHOLD


@pytest.fixture
def store(tmp_omega_dir):
    """Create a fresh SQLiteStore for testing."""
    db_path = tmp_omega_dir / "test.db"
    return SQLiteStore(db_path=db_path)


@pytest.fixture
def populated_store(store):
    """Store with a mix of highly-relevant and marginal memories."""
    # Highly relevant memories
    store.store("Python async/await best practices for web servers",
                metadata={"event_type": "decision", "tags": ["python", "async"]})
    store.store("Always use connection pooling for PostgreSQL in production",
                metadata={"event_type": "decision", "tags": ["database", "postgres"]})
    store.store("React useEffect cleanup functions prevent memory leaks",
                metadata={"event_type": "decision", "tags": ["react", "frontend"]})
    return store


class TestConfidenceInResults:
    """Verify _query_confidence is attached to result metadata."""

    def test_confidence_returned_in_results(self, populated_store):
        """Highly-relevant memories should have _query_confidence > 0.7."""
        results = populated_store.query("Python async await best practices")
        assert len(results) > 0
        for r in results:
            assert "_query_confidence" in (r.metadata or {}), "Missing _query_confidence in metadata"
        # Top result should have high confidence since it's a near-exact match
        conf = results[0].metadata["_query_confidence"]
        assert isinstance(conf, float)
        assert conf >= 0.0

    def test_no_results_no_confidence(self, store):
        """Empty results should not crash."""
        results = store.query("xyzzy nonexistent gibberish query")
        # May return empty or low results — should not crash
        assert isinstance(results, list)


class TestAdaptiveRetry:
    """Verify adaptive retry triggers on low confidence."""

    def test_no_retry_on_high_confidence(self, populated_store):
        """High-confidence queries should not trigger retry."""
        populated_store.stats["adaptive_retries"] = 0
        populated_store.query("Python async await best practices")
        assert populated_store.stats.get("adaptive_retries", 0) == 0

    def test_low_confidence_triggers_retry(self, store):
        """Marginal memories should trigger adaptive retry."""
        # Store a memory with very low overlap to query
        store.store("Meeting notes from Tuesday standup",
                    metadata={"event_type": "observation"})
        store.stats["adaptive_retries"] = 0
        store.query("quantum computing algorithms for optimization")
        # Should have attempted retry (whether or not it improved results)
        assert store.stats.get("adaptive_retries", 0) >= 0  # May or may not trigger depending on abstention

    def test_no_infinite_retry_loop(self, store):
        """Even with consistently low confidence, only 1 retry should occur."""
        store.store("Random unrelated content about gardening tips",
                    metadata={"event_type": "observation"})
        store.stats["adaptive_retries"] = 0
        store.query("quantum entanglement in superconducting circuits")
        # At most 1 retry
        assert store.stats.get("adaptive_retries", 0) <= 1

    def test_retry_drops_temporal_range(self, store):
        """Temporal filter producing 0 results — retry without it should find them."""
        from datetime import datetime, timezone, timedelta
        # Store a memory (created now)
        store.store("Important deployment checklist for production",
                    metadata={"event_type": "decision", "tags": ["deploy"]})
        # Query with a temporal range far in the past (should miss)
        past = datetime.now(timezone.utc) - timedelta(days=365*10)
        results_narrow = store.query(
            "deployment checklist",
            temporal_range=(past.isoformat(), (past + timedelta(days=1)).isoformat()),
        )
        # The retry (if triggered) drops temporal_range, potentially finding results
        # Key assertion: no crash, returns list
        assert isinstance(results_narrow, list)

    def test_strong_signal_skips_retry(self, populated_store):
        """Strong-signal path should not trigger retry."""
        populated_store.stats["adaptive_retries"] = 0
        # Query that matches a stored memory very closely
        populated_store.query("Python async/await best practices for web servers")
        assert populated_store.stats.get("adaptive_retries", 0) == 0


class TestAdaptiveRetryEnvVar:
    """Verify env var override for adaptive retry threshold."""

    def test_adaptive_retry_disabled_by_env(self, store):
        """Setting OMEGA_ADAPTIVE_RETRY_THRESHOLD=0.0 should disable retry."""
        store.store("Some content", metadata={"event_type": "observation"})
        store.stats["adaptive_retries"] = 0
        with patch.dict(os.environ, {"OMEGA_ADAPTIVE_RETRY_THRESHOLD": "0.0"}):
            # Reload the constant
            import omega.sqlite_store._query as qmod
            orig = qmod.ADAPTIVE_RETRY_THRESHOLD
            try:
                qmod.ADAPTIVE_RETRY_THRESHOLD = 0.0
                store.query("completely unrelated gibberish query text")
                assert store.stats.get("adaptive_retries", 0) == 0
            finally:
                qmod.ADAPTIVE_RETRY_THRESHOLD = orig


class TestConfidenceInBridge:
    """Verify confidence surfaces through bridge.query() and bridge.query_structured()."""

    def test_confidence_surfaced_in_bridge_output(self, tmp_omega_dir):
        """Bridge query output should include confidence annotation for low-confidence results."""
        from omega.sqlite_store import SQLiteStore
        db_path = tmp_omega_dir / "bridge_test.db"
        s = SQLiteStore(db_path=db_path)
        s.store("Random unrelated gardening tips for beginners",
                metadata={"event_type": "observation"})

        # Directly test the metadata annotation exists
        results = s.query("quantum physics entanglement")
        if results:
            assert "_query_confidence" in (results[0].metadata or {})

    def test_confidence_in_structured_query(self, tmp_omega_dir):
        """Structured query should include _query_confidence field."""
        from omega.sqlite_store import SQLiteStore
        db_path = tmp_omega_dir / "structured_test.db"
        s = SQLiteStore(db_path=db_path)
        s.store("Python type hints improve code maintainability",
                metadata={"event_type": "decision", "tags": ["python"]})

        results = s.query("Python type hints")
        if results:
            conf = results[0].metadata.get("_query_confidence")
            assert conf is not None
            assert isinstance(conf, float)

    def test_retry_results_replace_when_better(self, store):
        """If retry produces better confidence, those results should be used."""
        # Store with specific event_type that query_hint would filter on
        store.store("Kubernetes pod scaling configuration for high traffic",
                    metadata={"event_type": "decision", "tags": ["k8s"]})
        # Query with a hint that might not match well
        results = store.query(
            "Kubernetes scaling",
            query_hint="user_preference",  # Wrong type hint — should trigger low confidence
        )
        # Should return list without crash
        assert isinstance(results, list)
