"""
Integration tests for P36 neuroscience items 151-155.
Run: python -m pytest tests/test_neuro_p36.py -v
"""
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest

ROOT = Path(__file__).resolve().parent.parent
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))


# ---------------------------------------------------------------------------
# Item 151: Working memory refresh rate
# ---------------------------------------------------------------------------
class TestItem151RefreshRate:

    def setup_method(self):
        from pulse.brain import working_memory_p36
        working_memory_p36.reset_refresh_count()

    def test_initial_count_is_zero(self):
        from pulse.brain.memory.working_memory_p36 import get_refresh_count
        assert get_refresh_count() == 0

    def test_increment_increases_count(self):
        from pulse.brain.memory.working_memory_p36 import increment_refresh_count, get_refresh_count
        increment_refresh_count(5)
        assert get_refresh_count() == 5

    def test_multiple_increments_accumulate(self):
        from pulse.brain.memory.working_memory_p36 import increment_refresh_count, get_refresh_count
        increment_refresh_count(3)
        increment_refresh_count(7)
        assert get_refresh_count() == 10

    def test_reset_zeroes_count(self):
        from pulse.brain.memory.working_memory_p36 import increment_refresh_count, reset_refresh_count, get_refresh_count
        increment_refresh_count(20)
        reset_refresh_count()
        assert get_refresh_count() == 0

    def test_status_below_threshold_not_volatile(self):
        from pulse.brain.memory.working_memory_p36 import get_refresh_rate_status
        status = get_refresh_rate_status()
        assert status["volatile"] is False
        assert status["warning"] is None

    def test_status_above_threshold_volatile(self):
        from pulse.brain.memory.working_memory_p36 import (
            increment_refresh_count, get_refresh_rate_status, _HIGH_REFRESH_THRESHOLD
        )
        increment_refresh_count(_HIGH_REFRESH_THRESHOLD)
        status = get_refresh_rate_status()
        assert status["volatile"] is True
        assert status["warning"] is not None
        assert "REFRESH RATE" in status["warning"]

    def test_status_has_required_keys(self):
        from pulse.brain.memory.working_memory_p36 import get_refresh_rate_status
        status = get_refresh_rate_status()
        for k in ("refresh_count", "volatile", "threshold", "warning"):
            assert k in status

    def test_negative_increment_ignored(self):
        from pulse.brain.memory.working_memory_p36 import increment_refresh_count, get_refresh_count
        increment_refresh_count(-5)
        assert get_refresh_count() == 0


# ---------------------------------------------------------------------------
# Item 152: Confidence distribution monitor
# ---------------------------------------------------------------------------
class TestItem152ConfidenceHistogram:

    def test_returns_required_keys(self):
        from pulse.brain.metacognition.metamemory_p36 import get_confidence_histogram
        mock_conn = MagicMock()
        mock_conn.execute.return_value.fetchall.return_value = []
        with patch("pulse.core.brain_db.get_conn", return_value=mock_conn):
            result = get_confidence_histogram()
        for k in ("buckets", "total", "uncertain_pct", "alert"):
            assert k in result

    def test_alert_fires_when_majority_uncertain(self):
        from pulse.brain.metacognition.metamemory_p36 import get_confidence_histogram
        # 8 low-conf items, 2 high-conf items returned per table call
        call_count = [0]

        def fake_execute(sql, *args):
            m = MagicMock()
            m.fetchall.return_value = [
                (0.1,), (0.1,), (0.2,), (0.15,), (0.05,), (0.25,), (0.1,), (0.2,),
                (0.8,), (0.9,),
            ]
            return m

        mock_conn = MagicMock()
        mock_conn.execute.side_effect = fake_execute
        with patch("pulse.core.brain_db.get_conn", return_value=mock_conn):
            result = get_confidence_histogram()
        assert result["alert"] is not None
        assert "UNCERTAIN" in result["alert"]

    def test_no_alert_when_brain_confident(self):
        from pulse.brain.metacognition.metamemory_p36 import get_confidence_histogram
        mock_conn = MagicMock()
        mock_conn.execute.return_value.fetchall.return_value = [
            (0.8,), (0.9,), (0.7,), (0.75,), (0.85,),
        ]
        with patch("pulse.core.brain_db.get_conn", return_value=mock_conn):
            result = get_confidence_histogram()
        assert result["alert"] is None

    def test_buckets_sum_equals_total(self):
        from pulse.brain.metacognition.metamemory_p36 import get_confidence_histogram
        mock_conn = MagicMock()
        mock_conn.execute.return_value.fetchall.return_value = [
            (0.1,), (0.25,), (0.5,), (0.7,), (0.9,),
        ]
        with patch("pulse.core.brain_db.get_conn", return_value=mock_conn):
            result = get_confidence_histogram()
        bucket_sum = sum(result["buckets"].values())
        assert bucket_sum == result["total"]

    def test_exception_fails_open(self):
        from pulse.brain.metacognition.metamemory_p36 import get_confidence_histogram
        with patch("pulse.core.brain_db.get_conn", side_effect=Exception("db")):
            result = get_confidence_histogram()
        assert result["total"] == 0
        assert result["alert"] is None


# ---------------------------------------------------------------------------
# Item 153: Response inhibition gate
# ---------------------------------------------------------------------------
class TestItem153ResponseInhibition:

    def setup_method(self):
        from pulse.brain.brain_query import briefing_ext
        briefing_ext._QUERY_FAILURE_LOG.clear()

    def test_no_failures_no_inhibition(self):
        from pulse.brain.brain_query.briefing_ext import check_response_inhibition
        result = check_response_inhibition()
        assert result == []

    def test_three_failures_triggers_inhibition(self):
        from pulse.brain.brain_query.briefing_ext import (
            record_query_outcome, check_response_inhibition
        )
        record_query_outcome("query1", failed=True)
        record_query_outcome("query2", failed=True)
        record_query_outcome("query3", failed=True)
        result = check_response_inhibition()
        assert len(result) == 1
        assert "RESPONSE INHIBITION" in result[0]

    def test_two_failures_then_success_no_inhibition(self):
        from pulse.brain.brain_query.briefing_ext import (
            record_query_outcome, check_response_inhibition
        )
        record_query_outcome("q1", failed=True)
        record_query_outcome("q2", failed=True)
        record_query_outcome("q3", failed=False)
        result = check_response_inhibition()
        assert result == []

    def test_fewer_than_window_no_inhibition(self):
        from pulse.brain.brain_query.briefing_ext import (
            record_query_outcome, check_response_inhibition,
            _INHIBITION_FAILURE_WINDOW
        )
        for _ in range(_INHIBITION_FAILURE_WINDOW - 1):
            record_query_outcome("q", failed=True)
        result = check_response_inhibition()
        assert result == []

    def test_inhibition_message_content(self):
        from pulse.brain.brain_query.briefing_ext import (
            record_query_outcome, check_response_inhibition,
            INHIBITION_MESSAGE
        )
        for _ in range(3):
            record_query_outcome("q", failed=True)
        result = check_response_inhibition()
        assert INHIBITION_MESSAGE in result

    def test_record_outcome_fails_open(self):
        from pulse.brain.brain_query.briefing_ext import record_query_outcome
        # Should not raise on edge-case input
        record_query_outcome("", failed=True)


# ---------------------------------------------------------------------------
# Item 154: Memory interference resolution
# ---------------------------------------------------------------------------
class TestItem154MemoryInterference:

    def test_contradicting_pair_suppresses_lower(self):
        from pulse.brain.brain_search.search_scoring_p36 import resolve_memory_interference
        results = {
            "lessons": [
                {"text": "always use connection pooling in database", "confidence": 0.9},
                {"text": "never use connection pooling in database", "confidence": 0.5},
            ]
        }
        count = resolve_memory_interference(results)
        assert count == 1
        suppressed = [it for it in results["lessons"] if it.get("_interference_suppressed")]
        assert len(suppressed) == 1
        assert suppressed[0]["confidence"] < 0.9

    def test_non_contradicting_items_unchanged(self):
        from pulse.brain.brain_search.search_scoring_p36 import resolve_memory_interference
        results = {
            "lessons": [
                {"text": "always test your code before deploying", "confidence": 0.8},
                {"text": "document your functions clearly", "confidence": 0.7},
            ]
        }
        count = resolve_memory_interference(results)
        assert count == 0
        for item in results["lessons"]:
            assert not item.get("_interference_suppressed")

    def test_winner_keeps_high_confidence(self):
        from pulse.brain.brain_search.search_scoring_p36 import resolve_memory_interference
        results = {
            "wins": [
                {"text": "always validate input data types", "confidence": 0.95},
                {"text": "never validate input data types", "confidence": 0.3},
            ]
        }
        resolve_memory_interference(results)
        winner = [it for it in results["wins"] if not it.get("_interference_suppressed")]
        assert winner[0]["confidence"] == 0.95

    def test_empty_results_no_crash(self):
        from pulse.brain.brain_search.search_scoring_p36 import resolve_memory_interference
        count = resolve_memory_interference({})
        assert count == 0

    def test_single_item_no_suppression(self):
        from pulse.brain.brain_search.search_scoring_p36 import resolve_memory_interference
        results = {"lessons": [{"text": "always use type hints", "confidence": 0.8}]}
        count = resolve_memory_interference(results)
        assert count == 0


# ---------------------------------------------------------------------------
# Item 155: Cognitive load balancing
# ---------------------------------------------------------------------------
class TestItem155CognitiveLoad:

    def test_returns_required_keys(self):
        from pulse.brain.metacognition.metamemory_p36 import get_cognitive_load_status
        with patch("pulse.core.interoception._get_signals", return_value={"agent_load": 3.0}):
            result = get_cognitive_load_status()
        for k in ("active_agents", "overloaded", "threshold", "recommendation"):
            assert k in result

    def test_not_overloaded_below_threshold(self):
        from pulse.brain.metacognition.metamemory_p36 import get_cognitive_load_status
        with patch("pulse.core.interoception._get_signals", return_value={"agent_load": 5.0}):
            result = get_cognitive_load_status()
        assert result["overloaded"] is False
        assert result["recommendation"] is None

    def test_overloaded_above_threshold(self):
        from pulse.brain.metacognition.metamemory_p36 import get_cognitive_load_status, _AGENT_OVERLOAD_THRESHOLD
        overload = float(_AGENT_OVERLOAD_THRESHOLD + 1)
        with patch("pulse.core.interoception._get_signals",
                   return_value={"agent_load": overload}):
            result = get_cognitive_load_status()
        assert result["overloaded"] is True
        assert "LOAD SHEDDING" in result["recommendation"]

    def test_exception_fails_open(self):
        from pulse.brain.metacognition.metamemory_p36 import get_cognitive_load_status
        with patch("pulse.core.interoception._get_signals", side_effect=Exception("err")):
            result = get_cognitive_load_status()
        assert result["active_agents"] == 0
        assert result["overloaded"] is False
