from api.routes.complete import (
    _build_continuation_messages,
    _compute_effective_max_tokens,
    _merge_with_overlap,
    _should_recover_quality,
)


def test_compute_effective_max_tokens_prefers_quality_floor_for_explanations():
    eff, meta = _compute_effective_max_tokens(
        requested_max_tokens=200,
        task_mode="explanation",
        context_window_tokens=64000,
        estimated_input_tokens=2000,
    )
    assert eff is None
    assert meta["task_mode"] == "explanation"
    assert meta["adaptive_enabled"] is False


def test_compute_effective_max_tokens_clamps_under_context_pressure():
    eff, meta = _compute_effective_max_tokens(
        requested_max_tokens=4000,
        task_mode="explanation",
        context_window_tokens=4096,
        estimated_input_tokens=2800,
    )
    assert eff is None


def test_should_recover_quality_for_short_length_response():
    should, reason = _should_recover_quality(
        text="To prevent truncation, ensure",
        finish_reason="length",
        tool_calls=None,
    )
    assert should is True
    assert reason in ("too_short_length", "incomplete_length")


def test_should_not_recover_for_valid_tool_turn():
    should, reason = _should_recover_quality(
        text="",
        finish_reason="tool_calls",
        tool_calls=[{"id": "call_1"}],
    )
    assert should is False
    assert reason == "tool_turn"


def test_should_recover_for_short_incomplete_stop_response():
    should, reason = _should_recover_quality(
        text="I extracted the helper and now I will",
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is True
    assert reason == "incomplete_short_stop"


def test_should_recover_for_short_planning_stop_response():
    should, reason = _should_recover_quality(
        text="I'll start by checking routing_service.py",
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is True
    assert reason == "planning_short_stop"


def test_should_not_recover_when_planning_phrase_is_not_in_tail():
    txt = (
        "I'll check routing quickly, then proceed. "
        "This reply is complete, includes the final recommendation, and ends with punctuation."
    )
    should, reason = _should_recover_quality(
        text=txt,
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is False
    assert reason == ""


def test_should_not_recover_when_planning_phrase_is_outside_final_80_chars():
    txt = "I'll check routing first. " + ("x" * 90) + " Final recommendation is complete."
    should, reason = _should_recover_quality(
        text=txt,
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is False
    assert reason == ""


def test_should_recover_for_unclosed_code_fence_stop():
    should, reason = _should_recover_quality(
        text="Here is the fix:\n```python\nprint('hi')",
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is True
    assert reason == "unclosed_code_fence_stop"


def test_should_not_recover_for_closed_code_fence_stop():
    should, reason = _should_recover_quality(
        text="Here is the fix:\n```python\nprint('hi')\n```",
        finish_reason="stop",
        tool_calls=None,
    )
    assert should is False
    assert reason == ""


def test_build_continuation_messages_includes_system_note_and_tail_anchor():
    msgs = _build_continuation_messages([], "Alpha Beta Gamma")
    assert len(msgs) == 3
    assert msgs[0].role == "system"
    assert "cut off" in (msgs[0].content or "").lower()
    assert msgs[1].role == "assistant"
    assert "Alpha Beta Gamma" in (msgs[1].content or "")
    assert msgs[2].role == "user"
    assert "Last received tail" in (msgs[2].content or "")


def test_merge_with_overlap_avoids_duplicate_boundary():
    merged = _merge_with_overlap(
        "First sentence. Next step is to configure env vars",
        "configure env vars and restart the service.",
    )
    assert merged.count("configure env vars") == 1
    assert merged.endswith("restart the service.")


def test_merge_with_overlap_does_not_dedupe_tiny_overlap():
    merged = _merge_with_overlap(
        "Use variable",
        "variable names consistently.",
    )
    # 8-char overlap ("variable") is too small and should not be stripped.
    assert "variable variable" in merged
