"""Tests for uniq command functionality."""

import pytest

from e3po.editor import Editor, MarkMode, Mark


class MockScreen:
    """Mock curses screen for testing."""
    def __init__(self):
        self.height = 24
        self.width = 80

    def getmaxyx(self):
        return (self.height, self.width)

    def clear(self):
        pass

    def refresh(self):
        pass

    def addstr(self, *args):
        pass

    def move(self, row, col):
        pass

    def getch(self):
        return -1


def make_editor(lines=None):
    """Create an editor with mock screen for testing."""
    editor = Editor()
    editor.screen = MockScreen()
    editor.height = 24
    editor.width = 80
    editor.edit_height = 20
    editor.top_row = 0
    editor.left_col = 0
    if lines:
        editor.buffer.lines = lines.copy()
    return editor


class TestUniqNoMark:
    """Test uniq without any mark (entire file)."""

    def test_uniq_removes_adjacent_duplicates(self):
        editor = make_editor(["apple", "apple", "banana", "banana", "banana", "cherry"])
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["apple", "banana", "cherry"]

    def test_uniq_preserves_non_adjacent_duplicates(self):
        editor = make_editor(["apple", "banana", "apple", "cherry", "banana"])
        editor.do_uniq_command("uniq")
        # Non-adjacent duplicates should remain
        assert editor.buffer.lines == ["apple", "banana", "apple", "cherry", "banana"]

    def test_uniq_no_duplicates(self):
        editor = make_editor(["apple", "banana", "cherry"])
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["apple", "banana", "cherry"]
        assert "No duplicates" in editor.message

    def test_uniq_all_same(self):
        editor = make_editor(["same", "same", "same", "same"])
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["same"]

    def test_uniq_case_sensitive(self):
        editor = make_editor(["Apple", "apple", "APPLE"])
        editor.do_uniq_command("uniq")
        # Case sensitive: all three are different
        assert editor.buffer.lines == ["Apple", "apple", "APPLE"]

    def test_uniq_case_insensitive(self):
        editor = make_editor(["Apple", "apple", "APPLE", "banana"])
        editor.do_uniq_command("uniq -i")
        # Case insensitive: Apple, apple, APPLE are same
        assert len(editor.buffer.lines) == 2
        assert editor.buffer.lines[0] == "Apple"  # First one kept
        assert editor.buffer.lines[1] == "banana"


class TestUniqWithMark:
    """Test uniq with LINE mark."""

    def test_uniq_marked_lines_only(self):
        editor = make_editor(["header", "dup", "dup", "dup", "footer", "footer"])
        # Mark lines 1-3 (the "dup" lines)
        editor.mark = Mark(
            mode=MarkMode.LINE,
            start_row=1,
            start_col=0,
            end_row=3,
            end_col=0,
            pending=False
        )
        editor.do_uniq_command("uniq")
        # Should only uniq within mark, footer duplicates remain
        assert editor.buffer.lines == ["header", "dup", "footer", "footer"]

    def test_uniq_preserves_lines_outside_mark(self):
        editor = make_editor(["a", "a", "b", "b", "c", "c"])
        # Mark only middle section (lines 2-3)
        editor.mark = Mark(
            mode=MarkMode.LINE,
            start_row=2,
            start_col=0,
            end_row=3,
            end_col=0,
            pending=False
        )
        editor.do_uniq_command("uniq")
        # a,a at start and c,c at end should remain unchanged
        assert editor.buffer.lines[0] == "a"
        assert editor.buffer.lines[1] == "a"
        # Middle b,b becomes just b
        assert "c" in editor.buffer.lines

    def test_uniq_clears_mark(self):
        editor = make_editor(["dup", "dup", "dup"])
        editor.mark = Mark(
            mode=MarkMode.LINE,
            start_row=0,
            start_col=0,
            end_row=2,
            end_col=0,
            pending=False
        )
        editor.do_uniq_command("uniq")
        assert editor.mark is None


class TestUniqUndo:
    """Test that uniq can be undone."""

    def test_uniq_creates_undo(self):
        editor = make_editor(["apple", "apple", "banana"])
        original = editor.buffer.lines.copy()
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["apple", "banana"]
        # Undo should restore original
        editor.action_undo()
        assert editor.buffer.lines == original

    def test_uniq_marks_modified(self):
        editor = make_editor(["dup", "dup"])
        editor.buffer.modified = False
        editor.do_uniq_command("uniq")
        assert editor.buffer.modified == True


class TestUniqEdgeCases:
    """Test edge cases."""

    def test_uniq_single_line(self):
        editor = make_editor(["only one"])
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["only one"]
        assert "No duplicates" in editor.message

    def test_uniq_empty_lines(self):
        editor = make_editor(["", "", "text", "", ""])
        editor.do_uniq_command("uniq")
        assert editor.buffer.lines == ["", "text", ""]

    def test_uniq_whitespace_sensitive(self):
        editor = make_editor(["hello", "hello ", " hello", "hello"])
        editor.do_uniq_command("uniq")
        # Whitespace matters - all are different except last two
        assert editor.buffer.lines == ["hello", "hello ", " hello", "hello"]

    def test_unique_long_form(self):
        """Test 'unique' as alternate spelling."""
        editor = make_editor(["apple", "apple", "banana"])
        editor.do_uniq_command("unique")
        assert editor.buffer.lines == ["apple", "banana"]

    def test_unique_with_options(self):
        """Test 'unique -i' works."""
        editor = make_editor(["Apple", "apple", "APPLE", "banana"])
        editor.do_uniq_command("unique -i")
        assert len(editor.buffer.lines) == 2
