"""
Unit tests for DiffReviewManager parsing and presentation behavior.
"""

from unittest.mock import Mock

import pytest

import fenrirscreenreader.core.diffReviewManager as diff_review_module
from fenrirscreenreader.core.diffReviewManager import DiffReviewManager


@pytest.fixture
def diff_manager(monkeypatch):
    """Create a DiffReviewManager with a minimal test environment."""
    monkeypatch.setattr(diff_review_module, "_", lambda text: text)

    spoken_messages = []
    output_manager = Mock()

    def _capture_message(message, **_kwargs):
        spoken_messages.append(message)

    output_manager.present_text.side_effect = _capture_message
    settings_manager = Mock()
    settings_manager.get_setting.side_effect = (
        lambda section, setting: "compact"
        if (section, setting) == ("general", "diff_verbosity")
        else "default"
    )

    env = {
        "runtime": {
            "DebugManager": Mock(write_debug_out=Mock()),
            "OutputManager": output_manager,
            "SettingsManager": settings_manager,
            "MemoryManager": Mock(
                is_index_list_empty=Mock(return_value=True),
                get_index_list_element=Mock(return_value=""),
            ),
        },
        "bindings": {},
        "rawBindings": {},
    }

    manager = DiffReviewManager()
    manager.initialize(env)
    return manager, spoken_messages


@pytest.mark.unit
class TestDiffReviewManager:
    """Test diff review parsing and speech presentation edge cases."""

    def test_parse_unified_diff_tracks_sections_and_counts(self, diff_manager):
        manager, _ = diff_manager
        lines = [
            "diff --git a/example.txt b/example.txt",
            "index 1111111..2222222 100644",
            "--- a/example.txt",
            "+++ b/example.txt",
            "@@ -1,2 +1,3 @@",
            " context line",
            "-old line",
            "+new line one",
            "+new line two",
        ]

        manager._parse_lines(lines, "/tmp/example.diff")

        assert len(manager.file_sections) == 1
        assert len(manager.hunk_sections) == 1
        assert manager.total_added == 2
        assert manager.total_removed == 1
        assert manager.file_sections[0]["added_count"] == 2
        assert manager.file_sections[0]["removed_count"] == 1
        assert manager.hunk_sections[0]["position_in_file"] == 1
        assert manager.hunk_sections[0]["hunks_in_file"] == 1

    def test_formats_classic_diff_markers(self, diff_manager):
        manager, _ = diff_manager

        assert manager._format_classic_diff_command("17c17") == "line 17 changed"
        assert manager._format_classic_diff_command("17d16") == "line 17 deleted"
        assert manager._format_classic_diff_command("16a17") == "line 17 added"
        assert (
            manager._format_classic_diff_command("20,22c30,32")
            == "lines 20 through 22 changed"
        )
        assert manager._format_classic_diff_command("not a diff marker") is None

    def test_announces_classic_marker_line_as_plain_language(self, diff_manager):
        manager, spoken_messages = diff_manager

        manager._parse_lines(["17c17"], "/tmp/classic.diff")
        manager.current_line = 0
        manager._announce_current_line()

        assert spoken_messages[-1] == "line 17 changed"

    def test_marker_only_added_removed_lines_become_words(self, diff_manager):
        manager, spoken_messages = diff_manager

        manager._parse_lines(["+++", "---"], "/tmp/markers.diff")
        manager.current_line = 0
        manager._announce_current_line()
        manager.current_line = 1
        manager._announce_current_line()

        assert spoken_messages[-2] == "added"
        assert spoken_messages[-1] == "removed"

    def test_large_diff_parsing_stays_consistent(self, diff_manager):
        manager, spoken_messages = diff_manager
        line_count = 1500
        lines = [
            "diff --git a/large.txt b/large.txt",
            "--- a/large.txt",
            "+++ b/large.txt",
            "@@ -1,1500 +1,1500 @@",
        ]
        for index in range(1, line_count + 1):
            lines.append(f"-old value {index}")
            lines.append(f"+new value {index}")

        manager._parse_lines(lines, "/tmp/large.diff")
        manager.next_added()

        assert len(manager.file_sections) == 1
        assert len(manager.hunk_sections) == 1
        assert manager.total_added == line_count
        assert manager.total_removed == line_count
        assert manager.current_line == manager.added_lines[0]
        assert spoken_messages[-1].startswith("Added line.")

