"""
Unit tests for tab completion system.
"""
import pytest
from unittest.mock import MagicMock, patch

from terminal_client.completions import CompletionHelper, GameREPLCompletions


class TestCompletionHelper:
    """Tests for CompletionHelper utility class."""

    def test_filter_completions_exact_match(self):
        """Test filtering with exact match."""
        options = ['apple', 'apricot', 'banana']
        result = CompletionHelper.filter_completions('appl', options)
        assert result == ['apple']

    def test_filter_completions_no_match(self):
        """Test filtering with no matches."""
        options = ['apple', 'apricot', 'banana']
        result = CompletionHelper.filter_completions('cherry', options)
        assert result == []

    def test_filter_completions_empty_text(self):
        """Test filtering with empty text returns all."""
        options = ['apple', 'apricot', 'banana']
        result = CompletionHelper.filter_completions('', options)
        assert result == options

    def test_complete_option_with_prefix(self):
        """Test completing option with -- prefix."""
        available = ['league', 'home-team', 'away-team']
        result = CompletionHelper.complete_option('--le', 'cmd --le', available)
        assert result == ['--league']

    def test_complete_option_partial_match(self):
        """Test completing option with partial match."""
        available = ['league', 'home-team', 'away-team']
        result = CompletionHelper.complete_option('--ho', 'cmd --ho', available)
        assert result == ['--home-team']

    def test_complete_option_show_all(self):
        """Test showing all options when text is empty."""
        available = ['league', 'home-team']
        result = CompletionHelper.complete_option('', 'cmd ', available)
        assert set(result) == {'--league', '--home-team'}

    def test_complete_option_no_match(self):
        """Test completing option with no match."""
        available = ['league', 'home-team']
        result = CompletionHelper.complete_option('--invalid', 'cmd --invalid', available)
        assert result == []

    def test_get_current_option_simple(self):
        """Test getting current option from simple line."""
        line = 'defensive --alignment '
        result = CompletionHelper.get_current_option(line, len(line))
        assert result == 'alignment'

    def test_get_current_option_multiple(self):
        """Test getting current option with multiple options."""
        line = 'defensive --infield normal --alignment '
        result = CompletionHelper.get_current_option(line, len(line))
        assert result == 'alignment'

    def test_get_current_option_none(self):
        """Test getting current option when none present."""
        line = 'defensive '
        result = CompletionHelper.get_current_option(line, len(line))
        assert result is None

    def test_get_current_option_hyphen_to_underscore(self):
        """Test option name converts hyphens to underscores."""
        line = 'new_game --home-team '
        result = CompletionHelper.get_current_option(line, len(line))
        assert result == 'home_team'

    def test_get_current_option_mid_line(self):
        """Test getting current option when cursor is mid-line."""
        line = 'defensive --alignment normal --hold '
        result = CompletionHelper.get_current_option(line, len('defensive --alignment '))
        assert result == 'alignment'


class TestGameREPLCompletions:
    """Tests for GameREPLCompletions mixin."""

    @pytest.fixture
    def repl_completions(self):
        """Create GameREPLCompletions instance."""
        return GameREPLCompletions()

    def test_complete_new_game_options(self, repl_completions):
        """Test completing new_game options."""
        result = repl_completions.complete_new_game(
            '--', 'new_game --', 9, 11
        )
        assert '--league' in result
        assert '--home-team' in result
        assert '--away-team' in result

    def test_complete_new_game_option_partial(self, repl_completions):
        """Test completing new_game option with partial match."""
        result = repl_completions.complete_new_game(
            '--ho', 'new_game --ho', 9, 13
        )
        assert '--home-team' in result
        assert '--away-team' not in result

    def test_complete_new_game_league_value(self, repl_completions):
        """Test completing league value."""
        result = repl_completions.complete_new_game(
            's', 'new_game --league s', 9, 20
        )
        assert 'sba' in result
        assert 'pd' not in result

    def test_complete_new_game_league_all_values(self, repl_completions):
        """Test showing all league values."""
        result = repl_completions.complete_new_game(
            '', 'new_game --league ', 0, 19
        )
        assert 'sba' in result
        assert 'pd' in result

    def test_complete_defensive_options(self, repl_completions):
        """Test completing defensive options."""
        result = repl_completions.complete_defensive(
            '--', 'defensive --', 10, 12
        )
        assert '--alignment' in result
        assert '--infield' in result
        assert '--outfield' in result
        assert '--hold' in result

    def test_complete_defensive_alignment(self, repl_completions):
        """Test completing defensive alignment values."""
        result = repl_completions.complete_defensive(
            'shift', 'defensive --alignment shift', 10, 30
        )
        assert 'shifted_left' in result
        assert 'shifted_right' in result
        assert 'normal' not in result

    def test_complete_defensive_alignment_all(self, repl_completions):
        """Test showing all defensive alignment values."""
        result = repl_completions.complete_defensive(
            '', 'defensive --alignment ', 0, 24
        )
        assert 'normal' in result
        assert 'shifted_left' in result
        assert 'shifted_right' in result
        assert 'extreme_shift' in result

    def test_complete_defensive_infield(self, repl_completions):
        """Test completing defensive infield values."""
        result = repl_completions.complete_defensive(
            'dou', 'defensive --infield dou', 10, 25
        )
        assert 'double_play' in result
        assert 'normal' not in result

    def test_complete_defensive_hold_bases(self, repl_completions):
        """Test completing hold bases."""
        result = repl_completions.complete_defensive(
            '1,', 'defensive --hold 1,', 10, 19
        )
        assert '1,2' in result
        assert '1,3' in result

    def test_complete_defensive_hold_first_base(self, repl_completions):
        """Test completing first hold base."""
        result = repl_completions.complete_defensive(
            '', 'defensive --hold ', 0, 17
        )
        assert '1' in result
        assert '2' in result
        assert '3' in result

    def test_complete_offensive_options(self, repl_completions):
        """Test completing offensive options."""
        result = repl_completions.complete_offensive(
            '--', 'offensive --', 10, 12
        )
        assert '--approach' in result
        assert '--steal' in result
        assert '--hit-run' in result
        assert '--bunt' in result

    def test_complete_offensive_approach(self, repl_completions):
        """Test completing offensive approach values."""
        result = repl_completions.complete_offensive(
            'p', 'offensive --approach p', 10, 22
        )
        assert 'power' in result
        assert 'patient' in result
        assert 'normal' not in result

    def test_complete_offensive_approach_all(self, repl_completions):
        """Test showing all offensive approach values."""
        result = repl_completions.complete_offensive(
            '', 'offensive --approach ', 0, 21
        )
        assert 'normal' in result
        assert 'contact' in result
        assert 'power' in result
        assert 'patient' in result

    def test_complete_offensive_steal_bases(self, repl_completions):
        """Test completing steal bases."""
        result = repl_completions.complete_offensive(
            '', 'offensive --steal ', 0, 18
        )
        assert '2' in result
        assert '3' in result
        assert '1' not in result  # Can't steal first

    def test_complete_offensive_steal_multiple(self, repl_completions):
        """Test completing multiple steal bases."""
        result = repl_completions.complete_offensive(
            '2,', 'offensive --steal 2,', 10, 20
        )
        assert '2,3' in result

    def test_complete_quick_play_counts(self, repl_completions):
        """Test completing quick_play with common counts."""
        result = repl_completions.complete_quick_play(
            '1', 'quick_play 1', 11, 12
        )
        assert '1' in result
        assert '10' in result
        assert '100' in result

    def test_complete_quick_play_all_counts(self, repl_completions):
        """Test showing all quick_play counts."""
        result = repl_completions.complete_quick_play(
            '', 'quick_play ', 11, 11
        )
        assert '1' in result
        assert '5' in result
        assert '10' in result
        assert '27' in result
        assert '50' in result
        assert '100' in result

    @patch('app.core.state_manager.state_manager')
    def test_complete_use_game_with_games(self, mock_sm, repl_completions):
        """Test completing use_game with active games."""
        from uuid import uuid4

        game_id1 = uuid4()
        game_id2 = uuid4()
        mock_sm.list_games.return_value = [game_id1, game_id2]

        result = repl_completions.complete_use_game(
            str(game_id1)[:8], f'use_game {str(game_id1)[:8]}', 9, 17
        )

        # Should return the matching game ID
        assert any(str(game_id1) in r for r in result)

    @patch('app.core.state_manager.state_manager')
    def test_complete_use_game_no_games(self, mock_sm, repl_completions):
        """Test completing use_game with no active games."""
        mock_sm.list_games.return_value = []

        result = repl_completions.complete_use_game(
            '', 'use_game ', 9, 9
        )

        assert result == []

    def test_completedefault_with_option(self, repl_completions):
        """Test default completion with option prefix."""
        result = repl_completions.completedefault(
            '--', 'some_cmd --', 9, 11
        )
        assert '--help' in result
        assert '--verbose' in result
        assert '--debug' in result

    def test_completedefault_without_option(self, repl_completions):
        """Test default completion without option prefix."""
        result = repl_completions.completedefault(
            'text', 'some_cmd text', 9, 13
        )
        assert result == []

    def test_completenames_partial_command(self, repl_completions):
        """Test completing command name with partial text."""
        # Mock get_names to return command list
        repl_completions.get_names = lambda: ['do_new_game', 'do_defensive', 'do_offensive']

        result = repl_completions.completenames('new', None)
        assert 'new_game' in result

    def test_completenames_with_aliases(self, repl_completions):
        """Test completing command name includes aliases."""
        repl_completions.get_names = lambda: ['do_quit']

        result = repl_completions.completenames('q', None)
        assert 'quit' in result

    def test_completenames_exit_alias(self, repl_completions):
        """Test completing command name includes exit alias."""
        repl_completions.get_names = lambda: ['do_exit']

        result = repl_completions.completenames('ex', None)
        assert 'exit' in result
