"""P19 Neuroscience Refinements: Source Inspection Tests (Items 76-80)."""

ROOT = "C:/Users/ovall/Documents/projects/babel_bot/PULSE"
BRIEFING_PATH  = ROOT + "/pulse/brain/brain_query/briefing.py"
SE_PATH        = ROOT + "/pulse/brain/brain_search/search_engine.py"
TV_PATH        = ROOT + "/pulse/admin/audit/truth_verifier.py"
PD_PATH        = ROOT + "/pulse/daemons/neural/prediction_daemon.py"
JS_PATH        = ROOT + "/pulse/brain/save_writers/jsonl_store.py"


def _src(path):
    with open(path, encoding="utf-8") as f:
        return f.read()


def _lines(path):
    return _src(path).count("\n") + 1


def _block(src, marker, window=800):
    """Return `window` chars of source after `marker`."""
    idx = src.find(marker)
    if idx == -1:
        return ""
    return src[idx: idx + window]


# ===== Item 76: Habituation decay for repetitive queries =====

class TestItem76Habituation:

    def test_recent_queries_list_exists(self):
        assert "_RECENT_QUERIES" in _src(BRIEFING_PATH)

    def test_threshold_constant_exists(self):
        assert "_HABITUATION_THRESHOLD" in _src(BRIEFING_PATH)

    def test_threshold_value_is_3(self):
        src = _src(BRIEFING_PATH)
        assert "_HABITUATION_THRESHOLD = 3" in src or "_HABITUATION_THRESHOLD=3" in src

    def test_query_appended_to_list(self):
        src = _src(BRIEFING_PATH)
        assert "_RECENT_QUERIES.append(" in src

    def test_max_items_halved_on_repeat(self):
        src = _src(BRIEFING_PATH)
        assert "max_items // 2" in src or "_max_items // 2" in src

    def test_list_capped_at_10(self):
        src = _src(BRIEFING_PATH)
        assert "_RECENT_QUERIES" in src and "> 10" in src

    def test_fail_open_except(self):
        src = _src(BRIEFING_PATH)
        # The habituation block: find the append call, then look forward for except
        idx = src.find("_RECENT_QUERIES.append(")
        surrounding = src[max(0, idx - 50): idx + 300]
        assert "except Exception" in surrounding

    def test_briefing_file_under_300_lines(self):
        assert _lines(BRIEFING_PATH) <= 300, f"briefing.py has {_lines(BRIEFING_PATH)} lines"


# ===== Item 77: Novelty detection bonus =====

class TestItem77NoveltyBonus:

    def test_novelty_bonus_flag_exists(self):
        assert "_novelty_bonus" in _src(SE_PATH)

    def test_access_count_checked(self):
        src = _src(SE_PATH)
        assert "access_count" in src

    def test_access_count_zero_triggers_bonus(self):
        src = _src(SE_PATH)
        assert 'int(h.get("access_count", 0)) == 0' in src

    def test_confidence_boosted_by_0_1(self):
        src = _src(SE_PATH)
        block = _block(src, "_novelty_bonus")
        surrounding = src[max(0, src.find("_novelty_bonus") - 200): src.find("_novelty_bonus") + 200]
        assert "+ 0.1" in surrounding

    def test_confidence_capped_at_1_0(self):
        src = _src(SE_PATH)
        idx = src.find("_novelty_bonus")
        surrounding = src[max(0, idx - 250): idx + 100]
        assert "min(1.0," in surrounding

    def test_novelty_in_scoring_loop(self):
        # Must be inside the enrichment loop, after wilson_interval setup
        src = _src(SE_PATH)
        idx_novel = src.find("_novelty_bonus")
        idx_wilson = src.find("wilson_interval")
        assert idx_novel > idx_wilson  # novelty comes after wilson

    def test_fail_open_except(self):
        src = _src(SE_PATH)
        idx = src.find("_novelty_bonus")
        # except is AFTER the novelty_bonus assignment
        surrounding = src[max(0, idx - 100): idx + 100]
        assert "except Exception" in surrounding

    def test_search_engine_under_300_lines(self):
        assert _lines(SE_PATH) <= 300, f"search_engine.py has {_lines(SE_PATH)} lines"


# ===== Item 78: Confidence calibration audit =====

class TestItem78ConfidenceCalibration:

    def test_compute_calibration_function_exists(self):
        assert "_compute_calibration" in _src(TV_PATH)

    def test_returns_calibration_ratio(self):
        src = _src(TV_PATH)
        assert '"calibration_ratio"' in src

    def test_returns_total_high_conf(self):
        src = _src(TV_PATH)
        assert '"total_high_conf"' in src

    def test_returns_valid_count(self):
        src = _src(TV_PATH)
        assert '"valid_count"' in src

    def test_queries_confidence_ge_0_8(self):
        src = _src(TV_PATH)
        block = _block(src, "_compute_calibration", 800)
        assert "0.8" in block

    def test_queries_lessons_table(self):
        src = _src(TV_PATH)
        block = _block(src, "_compute_calibration", 800)
        assert "lessons" in block

    def test_fallback_returns_ratio_1_0(self):
        src = _src(TV_PATH)
        block = _block(src, "_compute_calibration", 800)
        assert '"calibration_ratio": 1.0' in block

    def test_fail_open_except(self):
        src = _src(TV_PATH)
        block = _block(src, "_compute_calibration", 800)
        assert "except Exception" in block

    def test_truth_verifier_under_300_lines(self):
        assert _lines(TV_PATH) <= 300, f"truth_verifier.py has {_lines(TV_PATH)} lines"


# ===== Item 79: Prediction confidence decay on no-feedback =====

class TestItem79NoFeedbackDecay:

    def test_decay_function_exists(self):
        assert "_decay_no_feedback_predictions" in _src(PD_PATH)

    def test_48_hour_threshold(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "48" in block

    def test_reduces_confidence_by_0_1(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "0.1" in block

    def test_minimum_confidence_floor_0_1(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "0.1" in block and "MAX" in block.upper()

    def test_only_decays_confidence_above_0_3(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "0.3" in block

    def test_updates_predictions_table(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "predictions" in block.lower()

    def test_called_from_run_daemon(self):
        src = _src(PD_PATH)
        daemon_block = _block(src, "def run_daemon", 400)
        assert "_decay_no_feedback_predictions" in daemon_block

    def test_fail_open_except(self):
        src = _src(PD_PATH)
        block = _block(src, "_decay_no_feedback_predictions", 700)
        assert "except Exception" in block

    def test_prediction_daemon_under_300_lines(self):
        assert _lines(PD_PATH) <= 300, f"prediction_daemon.py has {_lines(PD_PATH)} lines"


# ===== Item 80: Emotional contagion between items =====

class TestItem80EmotionalContagion:

    def test_emotional_contagion_comment_exists(self):
        assert "Item 80" in _src(JS_PATH)

    def test_emotion_threshold_0_7(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "0.7" in block

    def test_boosts_salience_nearby_items(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "salience" in block

    def test_boost_amount_is_0_2(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "0.2" in block

    def test_salience_capped_at_10(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "10.0" in block or "MIN(10.0" in block

    def test_applies_to_lessons_table(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "lessons" in block

    def test_applies_to_failures_table(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "failures" in block

    def test_uses_5_minute_window(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "minutes=5" in block

    def test_inside_build_jsonl_entry(self):
        src = _src(JS_PATH)
        # contagion block must come before end of build_jsonl_entry
        idx_contagion = src.find("Item 80")
        idx_return = src.find("    return entry")
        assert idx_contagion != -1 and idx_contagion < idx_return

    def test_fail_open_except(self):
        src = _src(JS_PATH)
        block = _block(src, "Item 80", 700)
        assert "except Exception" in block

    def test_jsonl_store_under_300_lines(self):
        assert _lines(JS_PATH) <= 300, f"jsonl_store.py has {_lines(JS_PATH)} lines"
