from __future__ import annotations

import json
from pathlib import Path

import pytest

from vibe.cli.history_manager import HistoryManager


def test_history_manager_normalizes_loaded_entries_like_numbers_to_strings(
    tmp_path: Path,
) -> None:
    # ideally, we would not use real I/O; but this test is a quick bugfix, thus it
    # does not intend to refactor the HistoryManager
    history_file = tmp_path / "history.jsonl"
    history_entries = ["hello", 123]
    history_file.write_text(
        "\n".join(json.dumps(entry) for entry in history_entries) + "\n",
        encoding="utf-8",
    )
    manager = HistoryManager(history_file)

    result = manager.get_previous(current_input="")

    assert result == "123"


def test_history_manager_retains_a_fixed_number_of_entries(tmp_path: Path) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file, max_entries=3)

    manager.add("first")
    manager.add("second")
    manager.add("third")
    manager.add("fourth")

    reloaded = HistoryManager(history_file)

    assert reloaded.get_previous(current_input="") == "fourth"
    assert reloaded.get_previous(current_input="") == "third"
    assert reloaded.get_previous(current_input="") == "second"
    # "first" is not proposed as we defined number of entries to 3
    assert reloaded.get_previous(current_input="") is None


def test_history_manager_filters_invalid_and_duplicated_entries(tmp_path: Path) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file, max_entries=5)
    manager.add("")  # empty
    manager.add("   ")  # is trimmed
    manager.add("first")
    manager.add("second")
    manager.add("second")  # duplicate
    manager.add("third")

    reloaded = HistoryManager(history_file)

    assert reloaded.get_previous(current_input="") == "third"
    assert reloaded.get_previous(current_input="") == "second"
    assert reloaded.get_previous(current_input="") == "first"
    assert reloaded.get_previous(current_input="") is None
    assert reloaded.get_previous(current_input="") is None


def test_history_manager_stores_slash_prefixed_entries(tmp_path: Path) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file, max_entries=5)
    manager.add("first")
    manager.add("/tool_call arg1 arg2")

    reloaded = HistoryManager(history_file)

    assert reloaded.get_previous(current_input="") == "/tool_call arg1 arg2"
    assert reloaded.get_previous(current_input="") == "first"
    assert reloaded.get_previous(current_input="") is None


def test_history_manager_keeps_entries_when_reload_read_fails(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file)
    manager.add("first")

    def raise_os_error(*args: object, **kwargs: object) -> None:
        raise OSError

    monkeypatch.setattr("vibe.cli.history_manager.read_safe", raise_os_error)

    manager.add("second")

    assert manager.get_previous(current_input="") == "second"
    assert manager.get_previous(current_input="") == "first"


def test_history_manager_resets_navigation_when_add_is_duplicate(
    tmp_path: Path,
) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file, max_entries=2)
    manager.add("a")
    manager.add("b")

    other = HistoryManager(history_file, max_entries=10)
    other.add("c")
    other.add("d")
    other.add("e")

    assert manager.get_previous(current_input="") == "b"
    manager.add("e")

    assert manager.get_previous(current_input="") == "e"
    assert manager.get_previous(current_input="") == "d"
    assert manager.get_previous(current_input="") is None


def test_history_manager_allows_navigation_round_trip(tmp_path: Path) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file)

    manager.add("alpha")
    manager.add("beta")

    assert manager.get_previous(current_input="typed") == "beta"
    assert manager.get_previous(current_input="typed") == "alpha"
    assert manager.get_next() == "beta"
    assert manager.get_next() == "typed"
    assert manager.get_next() is None


def test_history_manager_preserves_original_draft_during_navigation(
    tmp_path: Path,
) -> None:
    history_file = tmp_path / "history.jsonl"
    manager = HistoryManager(history_file)

    manager.add("foo")
    manager.add("bar")
    manager.add("fizz")

    assert manager.get_previous(current_input="draft") == "fizz"
    assert manager.get_previous(current_input="overwritten draft") == "bar"
    assert manager.get_next() == "fizz"
    assert manager.get_next() == "draft"
