"""
tests/test_shaping_directives.py — Tests for the emergent response shaping layer.

Covers:
  - _build_shaping_directives() output structure and correctness
  - _build_dynamic_boot_seed() output content and compression
  - _PATH_DIRECTIVES data integrity
  - _SEED_CORE, _SEED_PATHS, _SEED_PATTERNS data integrity
  - Integration: dusun() result includes shaping_directives and dynamic boot_seed

Design:
  KV₇: Each test function is independent — no shared state.
  T15: Structural tests (output shape) before detail tests (string content).
"""

from __future__ import annotations

import pytest


# ═══════════════════════════════════════════════════════════════════════
# SECTION 1: _PATH_DIRECTIVES data structure
# ═══════════════════════════════════════════════════════════════════════


class TestPathDirectives:
    """Tests for the _PATH_DIRECTIVES lookup table."""

    def test_path_directives_has_all_paths(self):
        from fw_server.dusun import _PATH_DIRECTIVES
        for path in ("P0", "P1", "P2", "P3", "P4"):
            assert path in _PATH_DIRECTIVES, f"Missing {path}"

    def test_each_entry_has_shape_and_guidance(self):
        from fw_server.dusun import _PATH_DIRECTIVES
        for path, info in _PATH_DIRECTIVES.items():
            assert "shape" in info, f"{path} missing 'shape'"
            assert "guidance" in info, f"{path} missing 'guidance'"
            assert isinstance(info["shape"], str)
            assert isinstance(info["guidance"], str)
            assert len(info["guidance"]) > 20, f"{path} guidance too short"


class TestKVLabels:
    """Tests for _KV_LABELS coverage."""

    def test_kv_labels_has_all_eight(self):
        from fw_server.dusun import _KV_LABELS
        for i in range(1, 9):
            assert f"KV{i}" in _KV_LABELS, f"Missing KV{i}"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 2: _build_shaping_directives()
# ═══════════════════════════════════════════════════════════════════════


class TestBuildShapingDirectives:
    """Tests for the shaping directives builder."""

    @pytest.fixture
    def base_kwargs(self):
        """Minimal valid kwargs for _build_shaping_directives."""
        return {
            "path": "P1",
            "grade": "Tasdik",
            "composite_score": 0.72,
            "patterns": ["three_phase_actualization", "transparent_vessels"],
            "anomalies": [],
            "kavaid": {"checks": {"KV1": True, "KV2": True, "KV3": True,
                                   "KV4": True, "KV5": True, "KV6": True,
                                   "KV7": True, "KV8": True}},
            "kavaid_pass_count": 8,
            "cross_validation": {},
            "sentinel_signal": None,
            "lens_scores": {"bayes": 0.65, "mereoloji": 0.58, "fol": 0.0},
        }

    def test_returns_dict(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert isinstance(result, dict)

    def test_has_required_keys(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        required = {
            "path_shape", "path_guidance", "grade_ceiling",
            "grade_source", "pattern_directives", "constraint_directives",
            "anomaly_directives", "convergence_directives",
            "sentinel_directives", "response_bounds", "lens_coverage",
        }
        assert required.issubset(result.keys())

    def test_path_shape_matches_path(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert result["path_shape"] == "structural_analysis"

    def test_grade_ceiling_from_input(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert result["grade_ceiling"] == "Tasdik"
        assert result["grade_source"] == "dusun"

    def test_kv4_breach_triggers_grade_override(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["composite_score"] = 0.97
        result = _build_shaping_directives(**base_kwargs)
        assert "grade_override" in result
        assert "0.95" in result["grade_override"]

    def test_no_grade_override_below_threshold(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert "grade_override" not in result

    def test_pattern_directives_populated(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        pat_dirs = result["pattern_directives"]
        assert isinstance(pat_dirs, list)
        assert len(pat_dirs) >= 1
        for pd in pat_dirs:
            assert "pattern" in pd
            assert "apply" in pd

    def test_constraint_directives_on_failure(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["kavaid"]["checks"]["KV7"] = False
        result = _build_shaping_directives(**base_kwargs)
        constraint_dirs = result["constraint_directives"]
        assert any("KV7" in d for d in constraint_dirs)

    def test_no_constraint_directives_when_all_pass(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert result["constraint_directives"] == []

    def test_anomaly_directives_zero_score(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["anomalies"] = ["ZERO-SCORE: fol returned 0.0"]
        result = _build_shaping_directives(**base_kwargs)
        anomaly_dirs = result["anomaly_directives"]
        assert len(anomaly_dirs) >= 1
        assert any("0.0" in d for d in anomaly_dirs)

    def test_anomaly_directives_kv4_breach(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["anomalies"] = ["KV4-BREACH: composite >= 0.95"]
        result = _build_shaping_directives(**base_kwargs)
        anomaly_dirs = result["anomaly_directives"]
        assert len(anomaly_dirs) >= 1

    def test_convergence_directives_tesanud(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["cross_validation"] = {"tesanud_detected": True}
        result = _build_shaping_directives(**base_kwargs)
        conv_dirs = result["convergence_directives"]
        assert any("Tesanud" in d for d in conv_dirs)

    def test_convergence_directives_infirad(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["cross_validation"] = {"infirad_detected": True}
        result = _build_shaping_directives(**base_kwargs)
        conv_dirs = result["convergence_directives"]
        assert any("Infirad" in d for d in conv_dirs)

    def test_sentinel_directives_with_signal(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        base_kwargs["sentinel_signal"] = {
            "taxonomy_id": "EF-01",
            "name": "Sycophancy",
            "confidence": 0.75,
        }
        result = _build_shaping_directives(**base_kwargs)
        sentinel_dirs = result["sentinel_directives"]
        assert len(sentinel_dirs) >= 1
        assert any("EF-01" in d for d in sentinel_dirs)

    def test_sentinel_directives_empty_without_signal(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        assert result["sentinel_directives"] == []

    def test_response_bounds_always_present(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        bounds = result["response_bounds"]
        assert isinstance(bounds, list)
        assert len(bounds) >= 4
        assert any("T17" in b for b in bounds)
        assert any("AX56" in b for b in bounds)
        assert any("KV4" in b for b in bounds)

    def test_lens_coverage_correct(self, base_kwargs):
        from fw_server.dusun import _build_shaping_directives
        result = _build_shaping_directives(**base_kwargs)
        lc = result["lens_coverage"]
        assert "active" in lc
        assert "zero" in lc
        assert "error" in lc
        assert "coverage_ratio" in lc
        # bayes=0.65, mereoloji=0.58 active; fol=0.0 zero
        assert "bayes" in lc["active"]
        assert "mereoloji" in lc["active"]
        assert "fol" in lc["zero"]
        assert lc["coverage_ratio"] == pytest.approx(2.0 / 3.0, abs=0.01)

    def test_all_five_paths(self):
        """Every path produces valid directives."""
        from fw_server.dusun import _build_shaping_directives
        for path_id in ("P0", "P1", "P2", "P3", "P4"):
            result = _build_shaping_directives(
                path=path_id,
                grade="Tasavvur",
                composite_score=0.5,
                patterns=[],
                anomalies=[],
                kavaid={"checks": {}},
                kavaid_pass_count=0,
                cross_validation={},
                sentinel_signal=None,
                lens_scores={},
            )
            assert result["path_shape"], f"{path_id} has empty path_shape"
            assert result["grade_ceiling"] == "Tasavvur"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 3: Boot Seed data structures
# ═══════════════════════════════════════════════════════════════════════


class TestSeedDataStructures:
    """Tests for _SEED_CORE, _SEED_PATHS, _SEED_PATTERNS."""

    def test_seed_core_has_kavaid(self):
        from fw_server.dusun import _SEED_CORE
        assert "KV1" in _SEED_CORE
        assert "KV8" in _SEED_CORE

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

    def test_seed_core_has_hayat_bridge(self):
        from fw_server.dusun import _SEED_CORE
        assert "HAYAT BRIDGE" in _SEED_CORE
        assert "Channel 1" in _SEED_CORE or "channel 1" in _SEED_CORE.lower()

    def test_seed_paths_has_all_five(self):
        from fw_server.dusun import _SEED_PATHS
        for path in ("P0", "P1", "P2", "P3", "P4"):
            assert path in _SEED_PATHS, f"Missing {path}"
            assert len(_SEED_PATHS[path]) > 10, f"{path} seed too short"

    def test_seed_patterns_non_empty(self):
        from fw_server.dusun import _SEED_PATTERNS
        assert len(_SEED_PATTERNS) >= 10
        for key, fragment in _SEED_PATTERNS.items():
            assert isinstance(fragment, str)
            assert len(fragment) > 5, f"{key} fragment too short"


# ═══════════════════════════════════════════════════════════════════════
# SECTION 4: _build_dynamic_boot_seed()
# ═══════════════════════════════════════════════════════════════════════


class TestBuildDynamicBootSeed:
    """Tests for the dynamic boot seed builder."""

    def test_returns_string(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(path="P1", patterns=[], anomalies=[])
        assert isinstance(result, str)

    def test_always_includes_core(self):
        from fw_server.dusun import _build_dynamic_boot_seed, _SEED_CORE
        result = _build_dynamic_boot_seed(path="P0", patterns=[], anomalies=[])
        # Core content should be in the output
        assert "KV1" in result
        assert "BOUNDS" in result
        assert "GRADES" in result

    def test_includes_correct_path_section(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(path="P3", patterns=[], anomalies=[])
        assert "PATH P3" in result
        assert "Diagnosis" in result
        # Should NOT include other path sections
        assert "PATH P1" not in result
        assert "PATH P2" not in result

    def test_includes_detected_patterns(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(
            path="P1",
            patterns=["multiplicative_gate", "holographic_architecture"],
            anomalies=[],
        )
        assert "ACTIVE PATTERNS" in result
        assert "AX52" in result  # multiplicative_gate
        assert "AX37" in result  # holographic_architecture

    def test_omits_undetected_patterns(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(
            path="P1",
            patterns=["multiplicative_gate"],
            anomalies=[],
        )
        # holographic_architecture not in patterns, so AX37 should not appear
        # (unless it's in core or path section)
        if "ACTIVE PATTERNS" in result:
            active_section = result[result.index("ACTIVE PATTERNS"):]
            assert "AX37" not in active_section

    def test_anomaly_awareness(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(
            path="P1",
            patterns=[],
            anomalies=["ZERO-SCORE: fol", "LENS-ERROR: bayes"],
        )
        assert "ANOMALIES DETECTED: 2" in result
        assert "M4" in result  # roughness = signal

    def test_no_anomaly_section_when_clean(self):
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(path="P1", patterns=[], anomalies=[])
        assert "ANOMALIES DETECTED" not in result

    def test_shorter_than_static_boot_seed(self):
        """Dynamic seed should be smaller than the original static _BOOT_SEED."""
        from fw_server.dusun import _build_dynamic_boot_seed, _BOOT_SEED
        dynamic = _build_dynamic_boot_seed(
            path="P1",
            patterns=["three_phase_actualization"],
            anomalies=[],
        )
        # Dynamic seed focuses on the relevant path + patterns only
        # It should be meaningfully shorter than the ~100-line static seed
        assert len(dynamic) < len(_BOOT_SEED)

    def test_contains_hint_or_pattern_keyword(self):
        """Backward compat: existing tests check for HINT or PATTERN."""
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(
            path="P1",
            patterns=["three_phase_actualization"],
            anomalies=[],
        )
        upper = result.upper()
        assert "HINT" in upper or "PATTERN" in upper

    def test_contains_hayat_bridge_reference(self):
        """Backward compat: existing tests check for hayat bridge content."""
        from fw_server.dusun import _build_dynamic_boot_seed
        result = _build_dynamic_boot_seed(path="P1", patterns=[], anomalies=[])
        assert "hayat bridge" in result.lower()


# ═══════════════════════════════════════════════════════════════════════
# SECTION 5: Integration — dusun() includes new fields
# ═══════════════════════════════════════════════════════════════════════


class TestDusunIntegration:
    """Verify dusun() includes shaping_directives and dynamic boot_seed."""

    def test_result_has_shaping_directives(self):
        from fw_server.dusun import dusun
        result = dusun("AX5 states that Hayat is the integration prerequisite.")
        assert "shaping_directives" in result
        sd = result["shaping_directives"]
        assert isinstance(sd, dict)
        assert "path_shape" in sd
        assert "grade_ceiling" in sd
        assert "response_bounds" in sd

    def test_result_boot_seed_is_dynamic(self):
        from fw_server.dusun import dusun
        result = dusun("Explain holographic architecture AX37.")
        boot = result.get("boot_seed", "")
        assert isinstance(boot, str)
        assert len(boot) > 100
        # Dynamic seed includes the classified path
        path = result["path"]
        assert f"PATH {path}" in boot

    def test_p0_has_shaping_directives(self):
        from fw_server.dusun import dusun
        result = dusun("hello")
        assert "shaping_directives" in result
        sd = result["shaping_directives"]
        assert sd["path_shape"] == "direct"

    def test_shaping_directives_grade_ceiling_matches_grade(self):
        from fw_server.dusun import dusun
        result = dusun("T15 structural claims above detail.")
        sd = result["shaping_directives"]
        assert sd["grade_ceiling"] == result["grade"]

    def test_lens_coverage_in_shaping_directives(self):
        from fw_server.dusun import dusun
        result = dusun("Compute bileshke composite convergence score.")
        sd = result["shaping_directives"]
        assert "lens_coverage" in sd
        lc = sd["lens_coverage"]
        assert "active" in lc
        assert "coverage_ratio" in lc


# ═══════════════════════════════════════════════════════════════════════
# SECTION 6: context.py — shaping_directives in _framework_context
# ═══════════════════════════════════════════════════════════════════════


class TestContextShapingDirectives:
    """Verify build_framework_context passes through shaping_directives."""

    def test_shaping_directives_injected(self):
        from fw_server.context import build_framework_context
        sd = {"path_shape": "structural_analysis", "grade_ceiling": "Tasdik"}
        ctx = build_framework_context("dusun", shaping_directives=sd)
        assert "shaping_directives" in ctx
        assert ctx["shaping_directives"]["path_shape"] == "structural_analysis"

    def test_none_shaping_directives_omitted(self):
        from fw_server.context import build_framework_context
        ctx = build_framework_context("dusun")
        assert "shaping_directives" not in ctx
