"""Tests for spell checking functionality."""

import pytest

from e3po.editor import Editor, SPELL_AVAILABLE


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

    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):
        self.last_move = (row, col)

    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


@pytest.mark.skipif(not SPELL_AVAILABLE, reason="pyspellchecker not installed")
class TestSpellMode:
    """Test spell checking mode."""

    def test_toggle_spell_mode_on(self):
        editor = make_editor(["hello world"])
        assert editor.spell_mode == False
        editor.toggle_spell_mode()
        assert editor.spell_mode == True

    def test_toggle_spell_mode_off(self):
        editor = make_editor(["hello world"])
        editor.toggle_spell_mode()  # On
        editor.toggle_spell_mode()  # Off
        assert editor.spell_mode == False

    def test_scan_finds_misspellings(self):
        editor = make_editor(["this is a tset of wrods"])
        editor.toggle_spell_mode()
        # Should find "tset" and "wrods" as misspelled
        assert len(editor.spell_errors) >= 1

    def test_spell_next_moves_cursor(self):
        editor = make_editor(["hello tset world"])
        editor.cursor_row = 0
        editor.cursor_col = 0
        editor.toggle_spell_mode()

        if editor.spell_errors:
            editor._spell_next()
            # Cursor should move to the misspelled word
            assert editor.cursor_row == 0
            # Should be at start of "tset" (position 6)
            assert editor.cursor_col > 0

    def test_spell_prev_moves_cursor(self):
        editor = make_editor(["tset hello wrods"])
        editor.toggle_spell_mode()

        if len(editor.spell_errors) >= 2:
            editor._spell_next()  # Go to first
            editor._spell_next()  # Go to second
            second_col = editor.cursor_col
            editor._spell_prev()  # Back to first
            assert editor.cursor_col < second_col

    def test_spell_skip_removes_word(self):
        editor = make_editor(["tset tset tset"])
        editor.toggle_spell_mode()
        initial_count = len(editor.spell_errors)

        if initial_count > 0:
            editor._spell_next()
            editor._spell_skip()
            # All instances of "tset" should be skipped now
            assert len(editor.spell_errors) < initial_count

    def test_get_misspelled_cols(self):
        editor = make_editor(["hello tset world"])
        editor.toggle_spell_mode()

        # Returns (other_cols, current_cols) tuple
        other_cols, current_cols = editor.get_misspelled_cols(0)
        # Should have columns marked for "tset"
        if editor.spell_errors:
            # Before navigating, all errors are in other_cols
            assert len(other_cols) > 0 or len(current_cols) > 0

    def test_get_misspelled_cols_current_vs_other(self):
        """Test that current spell error is distinguished from others."""
        editor = make_editor(["tset hello wrods"])
        editor.toggle_spell_mode()

        if len(editor.spell_errors) >= 2:
            # Navigate to first error
            editor._spell_next()
            other_cols, current_cols = editor.get_misspelled_cols(0)
            # Current error should be in current_cols
            assert len(current_cols) > 0
            # Other error should be in other_cols
            assert len(other_cols) > 0

    def test_spell_suggestions_populated(self):
        """Test that suggestions are populated when navigating."""
        editor = make_editor(["hello tset world"])
        editor.toggle_spell_mode()

        if editor.spell_errors:
            # Before navigating, no suggestions
            assert editor.spell_suggestions == []
            editor._spell_next()
            # After navigating, suggestions should be populated
            # (may be empty list if no suggestions, but should be populated)
            assert isinstance(editor.spell_suggestions, list)


@pytest.mark.skipif(not SPELL_AVAILABLE, reason="pyspellchecker not installed")
class TestSpellReplace:
    """Test spell replacement functionality."""

    def test_spell_replace_changes_word(self):
        editor = make_editor(["hello tset world"])
        editor.toggle_spell_mode()

        if editor.spell_errors:
            editor._spell_next()
            original_line = editor.buffer.lines[0]

            # Try to replace with first suggestion
            editor._spell_replace(0)

            # Line should be different (word replaced)
            # Note: might be same if no suggestions available
            new_line = editor.buffer.lines[0]
            # At minimum, the operation should complete without error


@pytest.mark.skipif(not SPELL_AVAILABLE, reason="pyspellchecker not installed")
class TestSpellWithSyntax:
    """Test spell checking with syntax highlighting."""

    def test_keywords_not_flagged(self):
        # Python keywords shouldn't be flagged as misspelled
        editor = make_editor(["def foo():", "    return None"])
        # Note: Without actual syntax highlighting initialized,
        # this test just verifies no crash occurs
        editor.toggle_spell_mode()

        # "def" and "return" are real English words anyway,
        # but this tests the code path doesn't crash
        assert editor.spell_mode == True
