"""Protocol frame builders, hello-auth gate, and history trimming."""
import main


def test_frame_shapes():
    assert main.f_ready("abc") == {"type": "ready", "session": "abc"}
    assert main.f_ack() == {"type": "ack"}
    assert main.f_sentence(1, "Hi.", "warm") == {
        "type": "sentence", "seq": 1, "text": "Hi.", "emotion": "warm"}
    assert main.f_sentence(2, "Plain.", None)["emotion"] is None
    assert main.f_audio_start(3) == {"type": "audio_start", "seq": 3}
    assert main.f_audio_end(3) == {"type": "audio_end", "seq": 3}
    assert main.f_turn_end() == {"type": "turn_end"}
    assert main.f_error("boom") == {"type": "error", "message": "boom"}
    assert main.f_pong() == {"type": "pong"}


def test_sentence_always_precedes_audio_ordering_contract():
    # audio_start carries the same seq as its sentence — the client keys binary
    # to the most recent audio_start.
    s = main.f_sentence(5, "x", "dry")
    a = main.f_audio_start(5)
    assert s["seq"] == a["seq"]


def test_auth_gate_disabled_when_no_key(monkeypatch):
    monkeypatch.delenv("GATEWAY_KEY", raising=False)
    assert main._auth_ok(None) is True
    assert main._auth_ok("anything") is True


def test_auth_gate_enforced_with_key(monkeypatch):
    monkeypatch.setenv("GATEWAY_KEY", "s3cret")
    assert main._auth_ok("s3cret") is True
    assert main._auth_ok("wrong") is False
    assert main._auth_ok(None) is False


def test_history_trim_keeps_last_turns_at_user_boundary():
    sess = main.Session(ws=None)
    # build 50 user-turns, each user + assistant
    msgs = []
    for i in range(50):
        msgs.append({"role": "user", "content": f"u{i}"})
        msgs.append({"role": "assistant", "content": f"a{i}"})
    trimmed = sess._trim(msgs)
    users = [m for m in trimmed if m["role"] == "user"]
    assert len(users) == main.MAX_TURNS
    assert trimmed[0]["role"] == "user"          # starts at a clean boundary
    assert trimmed[0]["content"] == "u10"        # 50 - 40


def test_history_trim_noop_when_under_cap():
    sess = main.Session(ws=None)
    msgs = [{"role": "user", "content": "u"},
            {"role": "assistant", "content": "a"}]
    assert sess._trim(msgs) == msgs


def test_compose_user_adds_typed_marker_and_tone():
    sess = main.Session(ws=None)
    typed = sess._compose_user({"text": "hello", "source": "typed"})
    assert typed.startswith("[TYPED] ")
    toned = sess._compose_user({"text": "go", "tone": "fast, urgent"})
    assert "(voice: fast, urgent)" in toned
    passthru = sess._compose_user({"text": "go", "tone": "(voice: laughing)"})
    assert passthru.count("(voice:") == 1        # already-wrapped tone kept as-is
