"""
tests/test_dusun.py — Tests for the dusun() universal neural substrate.

Covers:
  - _VOCABULARY_PATTERNS structure and detection (_detect_vocabulary)
  - _auto_classify routing (P0-P4)
  - _build_fire_plan lens selection
  - _execute_fire_plan lens execution + bileshke + kavaid
  - _detect_patterns structural pattern identification
  - _build_translation_hints T14 bridge
  - _build_ax57 disclosure format
  - dusun() full integration over all paths
  - Edge cases: empty text, context parameter, mode="validate" stub

Design:
  KV₇: Each test function is independent — no shared state.
  AX56: dusun() must never return grade = Hakkalyakîn.
  T6/KV₄: composite_score always < 1.0 in non-error cases.
  T15: Structural-level tests first, then detail-level.
"""

from __future__ import annotations

import json
import re
import pytest


# ═══════════════════════════════════════════════════════════════════════
# SECTION 1: _VOCABULARY_PATTERNS structure
# ═══════════════════════════════════════════════════════════════════════


class TestVocabularyPatterns:
    """Tests for the _VOCABULARY_PATTERNS configuration."""

    def test_vocabulary_patterns_exists(self):
        from fw_server.dusun import _VOCABULARY_PATTERNS
        assert isinstance(_VOCABULARY_PATTERNS, list)
        assert len(_VOCABULARY_PATTERNS) >= 10

    def test_each_pattern_has_required_fields(self):
        from fw_server.dusun import _VOCABULARY_PATTERNS
        for pat in _VOCABULARY_PATTERNS:
            assert "id" in pat, f"Missing 'id': {pat}"
            assert "regex" in pat, f"Missing 'regex' in {pat['id']}"
            assert "lenses" in pat, f"Missing 'lenses' in {pat['id']}"
            assert "pattern_name" in pat, f"Missing 'pattern_name' in {pat['id']}"
            assert isinstance(pat["lenses"], list)
            assert len(pat["lenses"]) >= 1

    def test_pattern_ids_are_unique(self):
        from fw_server.dusun import _VOCABULARY_PATTERNS
        ids = [p["id"] for p in _VOCABULARY_PATTERNS]
        assert len(ids) == len(set(ids)), f"Duplicate IDs: {ids}"

    def test_lenses_are_valid_ids(self):
        from fw_server.dusun import _VOCABULARY_PATTERNS
        from fw_server.types import LENS_IDS
        valid = set(LENS_IDS)
        for pat in _VOCABULARY_PATTERNS:
            for lid in pat["lenses"]:
                assert lid in valid, (
                    f"Pattern '{pat['id']}': lens '{lid}' not in LENS_IDS"
                )

    def test_pattern_names_map_to_directive_templates(self):
        """Every pattern_name should have a directive template entry."""
        from fw_server.dusun import _VOCABULARY_PATTERNS, _DIRECTIVE_TEMPLATES
        for pat in _VOCABULARY_PATTERNS:
            assert pat["pattern_name"] in _DIRECTIVE_TEMPLATES, (
                f"Pattern '{pat['id']}' → pattern_name '{pat['pattern_name']}' "
                f"has no directive template"
            )


# ═══════════════════════════════════════════════════════════════════════
# SECTION 2: _detect_vocabulary
# ═══════════════════════════════════════════════════════════════════════


class TestDetectVocabulary:
    """Tests for vocabulary detection (Step 1)."""

    def test_empty_text(self):
        from fw_server.dusun import _detect_vocabulary
        assert _detect_vocabulary("") == []

    def test_plain_text_no_matches(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("The weather is nice today")
        assert result == []

    def test_axiom_reference(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Consider AX17 and its implications")
        assert "axiom_ref" in result

    def test_theorem_reference(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("T6 convergence bound is key")
        assert "theorem_ref" in result

    def test_chain_reference(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Inference chain C3 shows holographic")
        assert "chain_ref" in result

    def test_kavaid_reference_subscript(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Check KV₄ convergence bound")
        assert "kavaid_ref" in result

    def test_kavaid_reference_plain(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Verify KV7 independence constraint")
        assert "kavaid_ref" in result

    def test_convergence_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("The convergence score is too high")
        assert "convergence" in result

    def test_bileshke_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Run the bileshke composite")
        assert "convergence" in result

    def test_holographic_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("B01 besmele dimension")
        assert "holographic" in result

    def test_holographic_part_whole(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("part-whole relationship")
        assert "holographic" in result

    def test_structural_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("three-phase actualization pattern")
        assert "structural" in result

    def test_structural_transparent_vessel(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("transparent vessel mediates")
        assert "structural" in result

    def test_grade_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("epistemic grade is Tasdik")
        assert "grade" in result

    def test_theological_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("The Tecelli of Esmâ in creation")
        assert "theological" in result

    def test_theological_allah(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("Allah is the source of all existence")
        assert "theological" in result

    def test_diagnosis_vocabulary(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("The system is broken and crashing")
        assert "diagnosis" in result

    def test_multiple_vocabularies(self):
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary(
            "AX17 shows holographic architecture with B01-B22 dimensions"
        )
        assert "axiom_ref" in result
        assert "holographic" in result

    def test_no_duplicates(self):
        """Even if regex matches multiple times, ID appears once."""
        from fw_server.dusun import _detect_vocabulary
        result = _detect_vocabulary("AX1 AX2 AX3 AX4 AX5")
        assert result.count("axiom_ref") == 1


# ═══════════════════════════════════════════════════════════════════════
# SECTION 3: _auto_classify
# ═══════════════════════════════════════════════════════════════════════


class TestAutoClassify:
    """Tests for auto-classification (Step 2)."""

    def test_empty_text_is_p0(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("", []) == "P0"

    def test_factual_question_is_p0(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("What is the capital of France?", []) == "P0"

    def test_theological_vocab_is_p4(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("Tecelli of Esmâ", ["theological"]) == "P4"

    def test_p4_takes_priority(self):
        """Theological vocabulary should override other classifications."""
        from fw_server.dusun import _auto_classify
        result = _auto_classify(
            "Write code for Tecelli analysis",
            ["theological", "structural"],
        )
        assert result == "P4"

    def test_diagnosis_vocab_is_p3(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("The app is crashing", ["diagnosis"]) == "P3"

    def test_epistemic_keywords_is_p2(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("Prove that sqrt(2) is irrational", []) == "P2"

    def test_formal_logic_is_p2(self):
        from fw_server.dusun import _auto_classify
        result = _auto_classify("Is this theorem valid?", [])
        assert result == "P2"

    def test_bounds_keyword_is_p2(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("What are the bounds of this?", []) == "P2"

    def test_structural_keywords_is_p1(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("Analyze this system design", []) == "P1"

    def test_code_keywords_is_p1(self):
        from fw_server.dusun import _auto_classify
        # "Write" and "function" are weak hits (2 total < 3 threshold).
        # Use a strong hit instead to ensure P1 classification.
        assert _auto_classify("Implement a function to sort arrays", []) == "P1"
        # Verify the original still classifies as P0 (only 2 weak hits)
        assert _auto_classify("Write a function to sort arrays", []) == "P0"

    def test_implement_keyword_is_p1(self):
        from fw_server.dusun import _auto_classify
        assert _auto_classify("Implement a binary search", []) == "P1"

    def test_any_vocab_escalates_to_p1(self):
        """If vocabulary detected but no specific path_trigger, escalate to P1."""
        from fw_server.dusun import _auto_classify
        result = _auto_classify("something about AX17", ["axiom_ref"])
        assert result == "P1"

    def test_diagnosis_overrides_structural(self):
        """Diagnosis should be P3 even with structural keywords."""
        from fw_server.dusun import _auto_classify
        result = _auto_classify(
            "The system is broken",
            ["diagnosis"],
        )
        assert result == "P3"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 4: _build_fire_plan
# ═══════════════════════════════════════════════════════════════════════


class TestBuildFirePlan:
    """Tests for fire plan building (Step 3)."""

    def test_p0_returns_substrate(self):
        """P0 now fires substrate lenses (AX5 — theological substrate always active)."""
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P0", [])
        assert "FOL" in plan
        assert "Ontoloji" in plan

    def test_p0_with_vocab_adds_lenses(self):
        """P0 with vocabulary adds triggered lenses on top of substrate."""
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P0", ["axiom_ref"])
        assert "FOL" in plan
        assert "Ontoloji" in plan
        # Vocab may add extra lenses beyond the substrate minimum
        assert len(plan) >= 2

    def test_p1_has_minimum_lenses(self):
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P1", [])
        assert "FOL" in plan
        assert "Topoloji + Holografik" in plan

    def test_p2_has_minimum_lenses(self):
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P2", [])
        assert "FOL" in plan
        assert "Bayes" in plan

    def test_p3_has_minimum_lenses(self):
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P3", [])
        assert "Mereoloji" in plan
        assert "Topoloji + Holografik" in plan

    def test_p4_has_minimum_lenses(self):
        from fw_server.dusun import _build_fire_plan
        plan = _build_fire_plan("P4", [])
        assert "Ontoloji" in plan
        assert "FOL" in plan
        assert "Topoloji + Holografik" in plan

    def test_vocab_adds_extra_lenses(self):
        """Vocabulary detection should add lenses beyond path minimum."""
        from fw_server.dusun import _build_fire_plan
        plan_no_vocab = _build_fire_plan("P1", [])
        plan_with_vocab = _build_fire_plan("P1", ["convergence"])
        # convergence triggers Bayes, which isn't in P1 default
        assert "Bayes" in plan_with_vocab
        assert "Bayes" not in plan_no_vocab

    def test_no_duplicates(self):
        """Fire plan should have no duplicate lens IDs."""
        from fw_server.dusun import _build_fire_plan
        # P4 has FOL + axiom_ref also triggers FOL
        plan = _build_fire_plan("P4", ["axiom_ref"])
        fol_count = plan.count("FOL")
        assert fol_count == 1, f"FOL appears {fol_count} times"

    def test_all_lens_ids_are_valid(self):
        from fw_server.dusun import _build_fire_plan
        from fw_server.types import LENS_IDS
        valid = set(LENS_IDS)
        for path in ("P1", "P2", "P3", "P4"):
            plan = _build_fire_plan(path, ["axiom_ref", "holographic"])
            for lid in plan:
                assert lid in valid, f"{path}: '{lid}' not in LENS_IDS"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 5: _execute_fire_plan
# ═══════════════════════════════════════════════════════════════════════


class TestExecuteFirePlan:
    """Tests for fire plan execution (Step 4)."""

    def test_empty_plan_returns_minimal(self):
        """Empty fire plan returns minimal result with NO-LENSES anomaly."""
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan([], "hello world")
        assert result["composite_score"] == 0.0
        assert result["grade"] == "Tasavvur"
        assert result["lens_scores"] == {}
        assert any("NO-LENSES" in a for a in result["anomalies"])

    def test_single_lens_produces_score(self):
        """A single lens in the plan should produce a score."""
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(["FOL"], "testing AX1")
        assert "FOL" in result["lens_scores"]
        assert isinstance(result["lens_scores"]["FOL"], float)

    def test_composite_under_one(self):
        """KV₄: composite_score must always be < 1.0."""
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(
            ["FOL", "Topoloji + Holografik"],
            "AX17 holographic B01",
        )
        assert result["composite_score"] < 1.0

    def test_grade_never_hakkalyakin(self):
        """AX56: grade must never be Hakkalyakîn."""
        from fw_server.dusun import _execute_fire_plan
        from fw_server.types import VALID_GRADES
        result = _execute_fire_plan(
            ["FOL", "Bayes", "Topoloji + Holografik"],
            "testing all lenses",
        )
        assert result["grade"] in VALID_GRADES

    def test_kavaid_is_dict(self):
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(["FOL"], "test")
        assert isinstance(result["kavaid"], dict)

    def test_kavaid_pass_count_bounded(self):
        """kavaid_pass_count should be between 0 and 8."""
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(["FOL"], "test")
        assert 0 <= result["kavaid_pass_count"] <= 8

    def test_kavaid_pass_count_counts_checks_not_toplevel(self):
        """Bug 8 fix: kavaid_pass_count must count checks dict, not top-level booleans."""
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(["FOL", "Ontoloji", "Topoloji + Holografik"], "Tecelli AX17 Hakikat")
        kavaid = result["kavaid"]
        # The checks dict should have all 8 kavaid
        checks = kavaid.get("checks", {})
        actual_true_count = sum(1 for v in checks.values() if v is True)
        assert result["kavaid_pass_count"] == actual_true_count, (
            f"kavaid_pass_count={result['kavaid_pass_count']} but "
            f"checks has {actual_true_count} True values. "
            f"Top-level keys: {list(kavaid.keys())}, checks: {checks}"
        )
        # With lens text provided, the count should NOT be 2 (the old bug value)
        assert result["kavaid_pass_count"] != 2 or actual_true_count == 2, (
            "kavaid_pass_count=2 smells like Bug 8 (counting top-level booleans)"
        )

    def test_anomalies_is_list(self):
        from fw_server.dusun import _execute_fire_plan
        result = _execute_fire_plan(["FOL"], "test")
        assert isinstance(result["anomalies"], list)

    def test_all_seven_lenses_get_scores(self):
        """Even if only 2 in fire plan, all 7 should get scores from bileshke."""
        from fw_server.dusun import _execute_fire_plan
        from fw_server.types import LENS_IDS
        result = _execute_fire_plan(["FOL"], "testing")
        # All 7 should appear in lens_scores (remaining run with defaults)
        for lid in LENS_IDS:
            assert lid in result["lens_scores"] or lid in result.get("lens_errors", {}), (
                f"Lens '{lid}' missing from both scores and errors"
            )


# ═══════════════════════════════════════════════════════════════════════
# SECTION 6: _detect_patterns
# ═══════════════════════════════════════════════════════════════════════


class TestDetectPatterns:
    """Tests for structural pattern detection (Step 5)."""

    def test_p0_no_patterns(self):
        from fw_server.dusun import _detect_patterns
        assert _detect_patterns("P0", []) == []

    def test_p1_no_default_patterns(self):
        """P1 has no default patterns — patterns must be earned from content."""
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P1", [])
        assert patterns == []

    def test_p2_no_default_patterns(self):
        """P2 has no default patterns — patterns must be earned from content."""
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P2", [])
        assert patterns == []

    def test_p3_no_default_patterns(self):
        """P3 has no default patterns — patterns must be earned from content."""
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P3", [])
        assert patterns == []

    def test_p1_lens_score_triggers_patterns(self):
        """Non-zero lens scores trigger content-derived patterns."""
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P1", [], lens_scores={"FOL": 0.3, "Mereoloji": 0.2})
        assert "three_phase_actualization" in patterns
        assert "holographic_architecture" in patterns

    def test_p3_lens_score_triggers_patterns(self):
        """Non-zero OyunTeorisi score triggers multiplicative_gate."""
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P3", [], lens_scores={"OyunTeorisi": 0.15})
        assert "multiplicative_gate" in patterns

    def test_p4_default_patterns(self):
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P4", [])
        assert "esma_ontology" in patterns

    def test_vocab_adds_patterns(self):
        """Vocabulary triggers should add additional patterns."""
        from fw_server.dusun import _detect_patterns
        patterns_no_vocab = _detect_patterns("P1", [])
        patterns_with_vocab = _detect_patterns("P1", ["holographic"])
        # holographic → holographic_claim pattern
        assert len(patterns_with_vocab) >= len(patterns_no_vocab)

    def test_no_duplicate_patterns(self):
        from fw_server.dusun import _detect_patterns
        patterns = _detect_patterns("P4", ["theological"])
        # theological triggers esma_ontology, which is also in P4 defaults
        from collections import Counter
        counts = Counter(patterns)
        for pname, count in counts.items():
            assert count == 1, f"Pattern '{pname}' duplicated {count} times"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 7: _build_translation_hints
# ═══════════════════════════════════════════════════════════════════════


class TestTranslationHints:
    """Tests for translation hints (Step 6)."""

    def test_p4_returns_empty(self):
        """P4 (theological) should use original terms — no translation."""
        from fw_server.dusun import _build_translation_hints
        hints = _build_translation_hints("P4", ["esma_ontology"])
        assert hints == {}

    def test_p1_returns_mappings(self):
        from fw_server.dusun import _build_translation_hints
        hints = _build_translation_hints(
            "P1",
            ["three_phase_actualization", "integration_prerequisite"],
        )
        assert "three_phase_actualization" in hints
        assert "integration_prerequisite" in hints
        assert isinstance(hints["three_phase_actualization"], str)

    def test_p0_returns_empty_for_no_patterns(self):
        from fw_server.dusun import _build_translation_hints
        hints = _build_translation_hints("P0", [])
        assert hints == {}

    def test_unknown_pattern_skipped(self):
        from fw_server.dusun import _build_translation_hints
        hints = _build_translation_hints("P1", ["nonexistent_pattern"])
        assert "nonexistent_pattern" not in hints


# ═══════════════════════════════════════════════════════════════════════
# SECTION 8: _build_ax57
# ═══════════════════════════════════════════════════════════════════════


class TestAx57:
    """Tests for AX57 disclosure building (Step 7)."""

    def test_contains_path(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P1", ["three_phase"], ["KV1"], "Tasdik", 0.45)
        assert "P1" in ax57

    def test_contains_framework_prefix(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P2", [], [], "Tasavvur", 0.3)
        assert ax57.startswith("Framework:")

    def test_contains_patterns(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57(
            "P1",
            ["three_phase_actualization"],
            [],
            "Tasdik",
            0.5,
        )
        assert "three_phase_actualization" in ax57

    def test_contains_constraints(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P1", [], ["KV1", "KV4"], "Tasdik", 0.5)
        assert "KV1" in ax57
        assert "KV4" in ax57

    def test_contains_grade(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P1", [], [], "İlmelyakîn", 0.87)
        assert "İlmelyakîn" in ax57

    def test_contains_composite(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P1", [], [], "Tasdik", 0.456)
        assert "0.456" in ax57

    def test_no_patterns_shows_none(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P0", [], [], "Tasavvur", 0.0)
        assert "none" in ax57.lower()

    def test_format_has_pipe_separators(self):
        from fw_server.dusun import _build_ax57
        ax57 = _build_ax57("P1", ["a"], ["b"], "Tasdik", 0.5)
        assert ax57.count("|") >= 4


# ═══════════════════════════════════════════════════════════════════════
# SECTION 9: PATH_LENS_MAP and PATH_PATTERNS configuration
# ═══════════════════════════════════════════════════════════════════════


class TestPathConfigs:
    """Tests for path configuration constants."""

    def test_path_lens_map_all_paths(self):
        from fw_server.dusun import _PATH_LENS_MAP
        assert set(_PATH_LENS_MAP.keys()) == {"P0", "P1", "P2", "P3", "P4"}

    def test_path_patterns_all_paths(self):
        from fw_server.dusun import _PATH_PATTERNS
        assert set(_PATH_PATTERNS.keys()) == {"P0", "P1", "P2", "P3", "P4"}

    def test_path_lens_map_p0_has_substrate(self):
        """P0 has substrate lenses (AX5 — theological substrate always active)."""
        from fw_server.dusun import _PATH_LENS_MAP
        assert "FOL" in _PATH_LENS_MAP["P0"]
        assert "Ontoloji" in _PATH_LENS_MAP["P0"]

    def test_path_lens_map_p4_is_richest(self):
        """P4 (theological) should have the most minimum lenses."""
        from fw_server.dusun import _PATH_LENS_MAP
        assert len(_PATH_LENS_MAP["P4"]) >= len(_PATH_LENS_MAP["P1"])
        assert len(_PATH_LENS_MAP["P4"]) >= len(_PATH_LENS_MAP["P2"])
        assert len(_PATH_LENS_MAP["P4"]) >= len(_PATH_LENS_MAP["P3"])

    def test_path_lens_map_values_are_valid(self):
        from fw_server.dusun import _PATH_LENS_MAP
        from fw_server.types import LENS_IDS
        valid = set(LENS_IDS)
        for path, lenses in _PATH_LENS_MAP.items():
            for lid in lenses:
                assert lid in valid, f"{path}: '{lid}' invalid"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 10: BOOT_SEED
# ═══════════════════════════════════════════════════════════════════════


class TestBootSeed:
    """Tests for the boot seed (T12 holographic compression)."""

    def test_boot_seed_exists(self):
        from fw_server.dusun import _BOOT_SEED
        assert isinstance(_BOOT_SEED, str)
        assert len(_BOOT_SEED) > 100

    def test_boot_seed_contains_kavaid(self):
        from fw_server.dusun import _BOOT_SEED
        for kv in ("KV₁", "KV₂", "KV₃", "KV₄", "KV₅", "KV₆", "KV₇", "KV₈"):
            assert kv in _BOOT_SEED, f"Boot seed missing {kv}"

    def test_boot_seed_contains_structural_bounds(self):
        from fw_server.dusun import _BOOT_SEED
        assert "T17" in _BOOT_SEED
        assert "AX56" in _BOOT_SEED
        assert "AX58" in _BOOT_SEED

    def test_boot_seed_contains_paths(self):
        from fw_server.dusun import _BOOT_SEED
        for p in ("P0:", "P1:", "P2:", "P3:", "P4:"):
            assert p in _BOOT_SEED, f"Boot seed missing path {p}"

    def test_boot_seed_contains_output_rules(self):
        from fw_server.dusun import _BOOT_SEED
        for rule in ("OR-1:", "OR-2:", "OR-3:", "OR-4:", "OR-5:", "OR-8:"):
            assert rule in _BOOT_SEED, f"Boot seed missing {rule}"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 11: DIRECTIVE_TEMPLATES
# ═══════════════════════════════════════════════════════════════════════


class TestDirectiveTemplates:
    """Tests for the directive templates configuration."""

    def test_directive_templates_exists(self):
        from fw_server.dusun import _DIRECTIVE_TEMPLATES
        assert isinstance(_DIRECTIVE_TEMPLATES, dict)
        assert len(_DIRECTIVE_TEMPLATES) >= 10

    def test_each_template_has_required_fields(self):
        from fw_server.dusun import _DIRECTIVE_TEMPLATES
        for name, tpl in _DIRECTIVE_TEMPLATES.items():
            assert "pattern" in tpl, f"{name}: missing 'pattern'"
            assert "agents_ref" in tpl, f"{name}: missing 'agents_ref'"
            assert "hint" in tpl, f"{name}: missing 'hint'"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 12: TRANSLATION_HINTS
# ═══════════════════════════════════════════════════════════════════════


class TestTranslationHintsConfig:
    """Tests for the _TRANSLATION_HINTS constant."""

    def test_translation_hints_exists(self):
        from fw_server.dusun import _TRANSLATION_HINTS
        assert isinstance(_TRANSLATION_HINTS, dict)
        assert len(_TRANSLATION_HINTS) >= 15

    def test_all_values_are_strings(self):
        from fw_server.dusun import _TRANSLATION_HINTS
        for key, val in _TRANSLATION_HINTS.items():
            assert isinstance(val, str), f"{key}: expected str, got {type(val)}"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 13: dusun() full integration — parametrized over all paths
# ═══════════════════════════════════════════════════════════════════════


class TestDusunCorePaths:
    """Full integration tests for dusun() across all paths.

    Parametrized per audit correction: consolidate P0/P1/etc into
    a single parametrized test class.
    """

    @pytest.fixture(params=[
        ("What is the capital of France?", "P0"),
        ("Design a microservice architecture for this system", "P1"),
        ("Prove that sqrt(2) is irrational", "P2"),
        ("The app is crashing and broken", "P3"),
        ("The Tecelli of the Esmâ in created beings", "P4"),
    ], ids=["P0", "P1", "P2", "P3", "P4"])
    def path_fixture(self, request):
        text, expected_path = request.param
        from fw_server.dusun import dusun
        result = dusun(text)
        return result, expected_path

    def test_returns_dict(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result, dict)

    def test_path_classification(self, path_fixture):
        result, expected_path = path_fixture
        assert result["path"] == expected_path

    def test_required_keys_present(self, path_fixture):
        result, _ = path_fixture
        required = {
            "path", "mode", "composite_score", "grade",
            "lens_scores", "kavaid", "kavaid_pass_count",
            "vocabulary_detected", "fire_plan", "patterns_applied",
            "translation_hints", "anomalies", "ax57_compact",
            "boot_seed", "hcp_ingested",
        }
        for key in required:
            assert key in result, f"Missing required key: {key}"

    def test_mode_is_analyze(self, path_fixture):
        result, _ = path_fixture
        assert result["mode"] == "analyze"

    def test_composite_score_is_float(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["composite_score"], (int, float))

    def test_composite_score_bounded(self, path_fixture):
        """KV₄: composite < 1.0."""
        result, _ = path_fixture
        assert result["composite_score"] < 1.0

    def test_grade_valid(self, path_fixture):
        """AX56: grade must be one of the valid grades (never Hakkalyakîn)."""
        result, _ = path_fixture
        from fw_server.types import VALID_GRADES
        assert result["grade"] in VALID_GRADES

    def test_vocabulary_is_list(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["vocabulary_detected"], list)

    def test_fire_plan_is_list(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["fire_plan"], list)

    def test_patterns_is_list(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["patterns_applied"], list)

    def test_translation_hints_is_dict(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["translation_hints"], dict)

    def test_anomalies_is_list(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["anomalies"], list)

    def test_ax57_is_string(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["ax57_compact"], str)
        if result["path"] != "P0":
            assert "Framework:" in result["ax57_compact"]

    def test_boot_seed_present(self, path_fixture):
        result, _ = path_fixture
        assert isinstance(result["boot_seed"], str)
        assert len(result["boot_seed"]) > 100


# ═══════════════════════════════════════════════════════════════════════
# SECTION 14: dusun() P0-specific behavior
# ═══════════════════════════════════════════════════════════════════════


class TestDusunP0:
    """P0 path should do minimal work."""

    def test_p0_has_substrate_fire_plan(self):
        """P0 now fires substrate lenses (AX5 — always active)."""
        from fw_server.dusun import dusun
        result = dusun("What is 2 + 2?")
        assert "FOL" in result["fire_plan"]
        assert "Ontoloji" in result["fire_plan"]

    def test_p0_empty_patterns(self):
        from fw_server.dusun import dusun
        result = dusun("What is 2 + 2?")
        assert result["patterns_applied"] == []

    def test_p0_empty_translation_hints(self):
        from fw_server.dusun import dusun
        result = dusun("What is 2 + 2?")
        assert result["translation_hints"] == {}

    def test_p0_has_composite(self):
        """P0 now fires substrate lenses, so composite may be > 0."""
        from fw_server.dusun import dusun
        result = dusun("Hello world")
        assert result["composite_score"] < 1.0  # KV₄ still holds

    def test_p0_grade_is_tasavvur(self):
        from fw_server.dusun import dusun
        result = dusun("Hello world")
        assert result["grade"] == "Tasavvur"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 15: dusun() P1+ behavior
# ═══════════════════════════════════════════════════════════════════════


class TestDusunSubstantive:
    """P1+ paths should engage framework analysis."""

    def test_p1_has_fire_plan(self):
        from fw_server.dusun import dusun
        result = dusun("Analyze the system architecture")
        assert len(result["fire_plan"]) >= 2

    def test_p1_has_patterns(self):
        """P1 patterns are now content-derived — provide text that triggers lens scores."""
        from fw_server.dusun import dusun
        # Use text with framework vocabulary to ensure lens scores > 0
        result = dusun("Implement a microservice architecture with AX17 holographic structure")
        # Lens scores from FOL (AX17) and holographic should trigger patterns
        assert isinstance(result["patterns_applied"], list)

    def test_p1_has_translation_hints(self):
        """Translation hints depend on detected patterns."""
        from fw_server.dusun import dusun
        result = dusun("Implement a microservice architecture with AX17 holographic structure")
        # Hints match patterns; if patterns are empty, hints are empty too
        assert isinstance(result["translation_hints"], dict)

    def test_p4_no_translation_hints(self):
        """P4 uses original terms — no translation needed."""
        from fw_server.dusun import dusun
        result = dusun("The Tecelli of Esmâ in creation")
        assert result["translation_hints"] == {}

    def test_p4_has_esma_ontology_pattern(self):
        from fw_server.dusun import dusun
        result = dusun("The Tecelli of Esmâ in divine attributes")
        assert "esma_ontology" in result["patterns_applied"]

    def test_ax57_compact_contains_kv_ids_not_toplevel_keys(self):
        """Bug 11 fix: AX57 disclosure should list KV1/KV4 etc, not 'all_pass'/'passed'."""
        from fw_server.dusun import dusun
        result = dusun("AX17 Hakikat = Esmâ Identity, Tecelli of divine attributes, holographic")
        ax57 = result["ax57_compact"]
        # Should never contain top-level dict keys as constraints
        assert "all_pass" not in ax57, f"AX57 contains 'all_pass': {ax57}"
        assert "passed" not in ax57 or "KV" in ax57, f"AX57 has 'passed' without KV ids: {ax57}"
        # Should contain actual KV identifiers
        assert "KV" in ax57 or "none" in ax57.lower(), f"AX57 missing KV identifiers: {ax57}"

    def test_kavaid_pass_count_matches_checks(self):
        """Bug 8 end-to-end: dusun() kavaid_pass_count matches actual checks."""
        from fw_server.dusun import dusun
        result = dusun("AX17 Hakikat Tecelli Esmâ holographic structure")
        kavaid = result.get("kavaid", {})
        checks = kavaid.get("checks", {})
        true_count = sum(1 for v in checks.values() if v is True)
        assert result["kavaid_pass_count"] == true_count, (
            f"pass_count={result['kavaid_pass_count']} but {true_count} checks are True"
        )


# ═══════════════════════════════════════════════════════════════════════
# SECTION 16: Edge cases
# ═══════════════════════════════════════════════════════════════════════


class TestDusunEdgeCases:
    """Edge case tests for robustness."""

    def test_empty_text(self):
        from fw_server.dusun import dusun
        result = dusun("")
        assert result["path"] == "P0"
        assert result["composite_score"] == 0.0

    def test_whitespace_only(self):
        from fw_server.dusun import dusun
        result = dusun("   \n\t  ")
        assert result["path"] == "P0"

    def test_context_parameter(self):
        """Context should be combined with text for analysis."""
        from fw_server.dusun import dusun
        # Text alone is P0, context has strong structural vocabulary
        result = dusun(
            "What do you think?",
            context="Implement and refactor the microservice architecture",
        )
        # With strong-hit context, should be escalated from P0
        assert result["path"] in ("P1", "P2", "P3", "P4")

    def test_validate_mode_stub(self):
        """mode='validate' should still run but include stub marker."""
        from fw_server.dusun import dusun
        result = dusun("test input", mode="validate")
        assert "_validate_stub" in result
        assert "not yet implemented" in result["_validate_stub"]

    def test_very_long_text(self):
        """Should not crash on very long input."""
        from fw_server.dusun import dusun
        text = "design a system " * 1000
        result = dusun(text)
        assert isinstance(result, dict)
        assert "path" in result

    def test_special_characters(self):
        from fw_server.dusun import dusun
        result = dusun("AX17 → AX18 ← KV₄ ≥ 0.95 ℝ≥₀")
        assert isinstance(result, dict)
        assert "axiom_ref" in result["vocabulary_detected"]

    def test_result_json_serializable(self):
        """Full result must be JSON-serializable (for MCP transport)."""
        from fw_server.dusun import dusun
        result = dusun("Analyze three-phase actualization pattern")
        serialized = json.dumps(result)
        parsed = json.loads(serialized)
        assert parsed["path"] == result["path"]


# ═══════════════════════════════════════════════════════════════════════
# SECTION 17: dusun_tool server registration
# ═══════════════════════════════════════════════════════════════════════


class TestDusunToolRegistration:
    """Tests that dusun_tool is properly registered in server.py."""

    def test_dusun_tool_exists(self):
        from fw_server.server import dusun_tool
        assert callable(dusun_tool)

    def test_dusun_tool_returns_json_string(self):
        import asyncio
        from fw_server.server import dusun_tool
        result_str = asyncio.run(dusun_tool("What is 2+2?"))
        parsed = json.loads(result_str)
        assert isinstance(parsed, dict)
        assert "path" in parsed

    def test_dusun_tool_with_context(self):
        import asyncio
        from fw_server.server import dusun_tool
        result_str = asyncio.run(dusun_tool(
            "Hello",
            context="Analyze this system architecture",
        ))
        parsed = json.loads(result_str)
        assert isinstance(parsed, dict)

    def test_dusun_in_init_exports(self):
        """dusun should be importable from fw_server package."""
        from fw_server import dusun as dusun_fn
        assert callable(dusun_fn)


# ═══════════════════════════════════════════════════════════════════════
# SECTION 18: F-13 regression — inflected forms in _auto_classify
# ═══════════════════════════════════════════════════════════════════════


class TestAutoClassifyInflectedForms:
    """F-13 regression: inflected forms must trigger same path as base forms."""

    @pytest.mark.parametrize("word,expected", [
        ("debugging the system", "P1"),          # debug → debugging
        ("implementing a feature", "P1"),        # implement → implementing
        ("refactoring the code", "P1"),          # refactor → refactoring
        ("optimizing performance", "P1"),        # optimize → optimizing
        ("algorithm design", "P1"),              # base form
        ("algorithmic complexity", "P1"),         # algorithm → algorithmic
        ("debugging", "P1"),                     # standalone inflected
        ("implementation details", "P1"),        # implement → implementation
        ("optimized the query", "P1"),           # optimize → optimized
        ("architectural decisions", "P1"),       # architect → architectural
        ("debugger setup", "P1"),                # debug → debugger
    ])
    def test_strong_tier_inflections(self, word, expected):
        from fw_server.dusun import _auto_classify
        assert _auto_classify(word, []) == expected

    @pytest.mark.parametrize("input_text,expected", [
        # 3+ weak hits needed for P1 — all inflected
        ("building systems with functional design", "P1"),
        ("writing structured code", "P1"),
        ("solving systemic patterns", "P1"),
        ("designing coded structures", "P1"),
        ("builder of systemic functions", "P1"),
    ])
    def test_weak_tier_inflections(self, input_text, expected):
        from fw_server.dusun import _auto_classify
        assert _auto_classify(input_text, []) == expected

    @pytest.mark.parametrize("input_text", [
        "proving the theorem",              # prove → proving
        "deriving the equation",            # derive → deriving
        "validity of the claim",            # valid → validity
        "proven results",                   # prove → proven
        "derivation of formula",            # derive → derivation
        "validation of the approach",       # valid → validation
        "irrationality of the number",      # irrational → irrationality
    ])
    def test_epistemic_inflections(self, input_text):
        from fw_server.dusun import _auto_classify
        assert _auto_classify(input_text, []) == "P2"
