"""TDD tests for runtime/conversation/prompt.py.

Key invariant: the pre-breakpoint prefix is byte-stable across turns
(same persona, different retrieved chunks → same stable prefix).
"""

from __future__ import annotations

import pytest
from runtime.conversation.prompt import assemble
from shared.package import PersonaManifest

PERSONA = PersonaManifest(
    slug="test-persona",
    display_name="Test Persona",
    born=100,
    died=180,
    voice_policy="generated",
    style_summary="Speaks in short, direct aphorisms.",
)


@pytest.fixture
def pkg_dir(test_persona_dir):
    return test_persona_dir


# ── assemble ─────────────────────────────────────────────────────────────────


def test_assemble_returns_system_and_breakpoint(pkg_dir):
    system, bp = assemble(PERSONA, pkg_dir)
    assert isinstance(system, str)
    assert isinstance(bp, int)
    assert bp > 0


def test_assemble_contains_identity(pkg_dir):
    system, _ = assemble(PERSONA, pkg_dir)
    assert "Test Persona" in system


def test_assemble_contains_era_guard(pkg_dir):
    system, _ = assemble(PERSONA, pkg_dir)
    assert "180" in system  # died year


def test_assemble_contains_misattribution_guard(pkg_dir):
    system, _ = assemble(PERSONA, pkg_dir)
    assert "NEVER invent a quote" in system


def test_assemble_contains_exemplars(pkg_dir):
    system, _ = assemble(PERSONA, pkg_dir)
    # test-persona has exemplars.jsonl
    assert "authentic voice" in system


def test_assemble_contains_retrieved_chunks(pkg_dir):
    chunks = [{"source_id": "src", "text": "Virtue is the only good."}]
    system, _ = assemble(PERSONA, pkg_dir, retrieved_chunks=chunks)
    assert "Virtue is the only good." in system
    assert "Relevant passages" in system


def test_cache_invariant_stable_prefix_byte_identical(pkg_dir):
    """The prefix before the cache breakpoint must be byte-identical across turns."""
    chunks_a = [{"source_id": "src", "text": "First retrieved chunk."}]
    chunks_b = [{"source_id": "src", "text": "Entirely different chunk."}]

    system_a, bp_a = assemble(PERSONA, pkg_dir, retrieved_chunks=chunks_a)
    system_b, bp_b = assemble(PERSONA, pkg_dir, retrieved_chunks=chunks_b)

    assert bp_a == bp_b, "Cache breakpoint must be identical across turns"

    prefix_a = system_a.encode("utf-8")[:bp_a]
    prefix_b = system_b.encode("utf-8")[:bp_b]
    assert prefix_a == prefix_b, "Stable prefix must be byte-identical across turns"


def test_cache_invariant_no_chunks_is_pure_stable(pkg_dir):
    """Without retrieved chunks, the full system is the stable prefix."""
    system, bp = assemble(PERSONA, pkg_dir, retrieved_chunks=None)
    assert len(system.encode("utf-8")) == bp


def test_assemble_no_exemplars_if_missing(tmp_path):
    """When exemplars.jsonl absent, exemplar block is skipped."""
    style_dir = tmp_path / "style"
    style_dir.mkdir(parents=True)
    # No exemplars.jsonl
    system, _ = assemble(PERSONA, tmp_path)
    assert "authentic voice" not in system


def test_assemble_persona_without_died(tmp_path):
    persona = PersonaManifest(
        slug="living",
        display_name="Living Person",
        voice_policy="generated",
    )
    system, _ = assemble(persona, tmp_path)
    assert "Living Person" in system
