"""Tests for System class and inner classes."""

import sys
from unittest.mock import MagicMock, patch

import pytest

from freyja import FreyjaCLI
from freyja.cli import SystemClassBuilder

System = SystemClassBuilder.build(True, True)


class TestSystem:
    """Test the System class initialization."""

    def test_system_initialization(self):
        """Test System class can be initialized with default config dir."""
        system = System()
        assert system is not None


class TestSystemTuneTheme:
    """Test the System.TuneTheme inner class."""

    def test_tune_theme_initialization_universal(self):
        """Test TuneTheme initializes with universal theme by default."""
        tuner = System().TuneTheme()
        assert tuner.use_colorful_theme is False
        assert tuner.adjust_percent == 0.0
        assert tuner.ADJUSTMENT_INCREMENT == 0.05

    def test_tune_theme_initialization_colorful(self):
        """Test TuneTheme initializes with colorful theme when specified."""
        tuner = System().TuneTheme(initial_theme="colorful")
        assert tuner.use_colorful_theme is True

    def test_increase_adjustment(self):
        """Test adjustment increase functionality."""
        tuner = System().TuneTheme()
        initial_adjustment = tuner.adjust_percent
        tuner.increase_adjustment()
        assert tuner.adjust_percent == initial_adjustment + tuner.ADJUSTMENT_INCREMENT

    def test_decrease_adjustment(self):
        """Test adjustment decrease functionality."""
        tuner = System().TuneTheme()
        tuner.adjust_percent = 0.10  # Set initial value
        tuner.decrease_adjustment()
        assert tuner.adjust_percent == 0.05

    def test_decrease_adjustment_minimum_bound(self):
        """Test adjustment decrease respects minimum bound."""
        tuner = System().TuneTheme()
        tuner.adjust_percent = -5.0  # Set at minimum
        tuner.decrease_adjustment()
        assert tuner.adjust_percent == -5.0  # Should not go lower

    def test_increase_adjustment_maximum_bound(self):
        """Test adjustment increase respects maximum bound."""
        tuner = System().TuneTheme()
        tuner.adjust_percent = 5.0  # Set at maximum
        tuner.increase_adjustment()
        assert tuner.adjust_percent == 5.0  # Should not go higher

    def test_toggle_theme(self):
        """Test theme toggling functionality."""
        tuner = System().TuneTheme()
        assert tuner.use_colorful_theme is False
        tuner.toggle_theme()
        assert tuner.use_colorful_theme is True
        tuner.toggle_theme()
        assert tuner.use_colorful_theme is False

    def test_select_strategy_with_valid_string(self):
        """Test strategy selection with valid string."""
        tuner = System().TuneTheme()
        tuner.select_strategy("COLOR_HSL")
        # Should set strategy without error
        from freyja.theme import AdjustStrategy

        assert tuner.adjust_strategy == AdjustStrategy.COLOR_HSL

    def test_select_strategy_with_invalid_string(self):
        """Test strategy selection with invalid string."""
        tuner = System().TuneTheme()
        original_strategy = tuner.adjust_strategy
        tuner.select_strategy("INVALID_STRATEGY")
        # Should not change strategy
        assert tuner.adjust_strategy == original_strategy

    def test_get_current_theme(self):
        """Test getting current theme with adjustments."""
        tuner = System().TuneTheme()
        theme = tuner.get_current_theme()
        assert theme is not None
        # Should return a theme object
        assert hasattr(theme, "title")
        assert hasattr(theme, "command_name")

    def test_individual_color_overrides(self):
        """Test individual color override functionality."""
        tuner = System().TuneTheme()
        assert len(tuner.individual_color_overrides) == 0

        # Add a color override
        from freyja.theme import RGB

        test_color = RGB.from_rgb(0xFF0000)  # Red
        tuner.individual_color_overrides["title"] = test_color
        tuner.modified_components.add("title")

        assert len(tuner.individual_color_overrides) == 1
        assert "title" in tuner.modified_components

        # Get theme with overrides
        theme = tuner.get_current_theme()
        assert theme.title.fg == test_color

    def test_reset_component_color(self):
        """Test resetting individual component colors."""
        tuner = System().TuneTheme()
        from freyja.theme import RGB

        test_color = RGB.from_rgb(0xFF0000)

        # Add override then reset
        tuner.individual_color_overrides["title"] = test_color
        tuner.modified_components.add("title")
        tuner._reset_component_color("title")

        assert "title" not in tuner.individual_color_overrides
        assert "title" not in tuner.modified_components

    def test_reset_all_individual_colors(self):
        """Test resetting all individual colors."""
        tuner = System().TuneTheme()
        from freyja.theme import RGB

        # Add multiple overrides
        tuner.individual_color_overrides["title"] = RGB.from_rgb(0xFF0000)
        tuner.individual_color_overrides["command_name"] = RGB.from_rgb(0x00FF00)
        tuner.modified_components.update(["title", "command_name"])

        tuner._reset_all_individual_colors()

        assert len(tuner.individual_color_overrides) == 0
        assert len(tuner.modified_components) == 0


class TestSystemCompletion:
    """Test the System.Completion inner class."""

    def test_completion_initialization(self):
        """Test Completion class initializes correctly."""
        completion = System().Completion()
        # Shell should auto-detect (could be bash, zsh, fish, etc.)
        assert completion.shell in ["bash", "zsh", "fish", "powershell"]
        assert completion._cli_instance is None
        assert completion._completion_handler is None

    def test_completion_initialization_with_cli(self):
        """Test Completion class initializes with FreyjaCLI instance."""
        mock_cli = MagicMock()
        completion = System.Completion(cli_instance=mock_cli)
        assert completion._cli_instance == mock_cli

    def test_completion_explicit_shell(self):
        """Test Completion class with explicitly specified shell."""
        completion = System().Completion(shell="bash")  # noqa: S604 # not subprocess, class param
        assert completion.shell == "bash"

        completion = System().Completion(shell="zsh")  # noqa: S604 # not subprocess, class param
        assert completion.shell == "zsh"

    def test_is_completion_request_false(self):
        """Test completion request detection returns False normally."""
        completion = System().Completion()
        # Patch sys.argv to not include completion flags
        with patch.object(sys, "argv", ["script.py"]):
            with patch("os.environ.get", return_value=None):
                assert completion.is_completion_request() is False

    def test_is_completion_request_true_argv(self):
        """Test completion request detection returns True with --_complete flag."""
        completion = System().Completion()
        with patch.object(sys, "argv", ["script.py", "--_complete"]):
            assert completion.is_completion_request() is True

    def test_is_completion_request_true_env(self):
        """Test completion request detection returns True with env var."""
        completion = System().Completion()
        with patch.object(sys, "argv", ["script.py"]):
            with patch("os.environ.get", return_value="1"):
                assert completion.is_completion_request() is True

    def test_install_completion_disabled(self):
        """Test install completion when completion is disabled."""
        mock_cli = MagicMock()
        mock_cli.enable_completion = False
        completion = System.Completion(cli_instance=mock_cli)

        result = completion.install()
        assert result is False

    def test_show_completion_disabled(self):
        """Test show completion when completion is disabled."""
        mock_cli = MagicMock()
        mock_cli.enable_completion = False
        completion = System.Completion(cli_instance=mock_cli)

        # Should not raise error, just print message
        completion.show("bash")

    def test_install_completion_no_cli_instance(self):
        """Test install completion without FreyjaCLI instance."""
        completion = System().Completion()
        result = completion.install()
        assert result is False

    @patch("sys.exit")
    def test_handle_completion_no_handler(self, mock_exit):
        """Test handle completion without completion handler."""
        completion = System().Completion()
        # Mock the init_completion to prevent actually initializing
        with patch.object(completion, "init_completion"):
            completion.handle_completion()
            # Should call exit once with code 1 when no handler is available
            mock_exit.assert_called_once_with(1)


class TestSystemCLIGeneration:
    """Test System class FreyjaCLI generation."""

    def test_system_cli_generation(self):
        """Test System class generates FreyjaCLI correctly."""
        cli = FreyjaCLI(System)
        cli.create_parser()

        # Should have System class as target
        assert cli.target_class == System
        assert cli.target_mode.value == "class"

    def test_system_cli_has_inner_classes(self):
        """Test System FreyjaCLI recognizes inner classes."""
        cli = FreyjaCLI(System)

        # Should discover inner classes as command groups
        assert "tune-theme" in cli.commands
        assert cli.commands["tune-theme"]["type"] == "group"
        assert "completion" in cli.commands
        assert cli.commands["completion"]["type"] == "group"

    def test_system_cli_command_structure(self):
        """Test System FreyjaCLI creates proper command structure."""
        cli = FreyjaCLI(System)

        # Should have hierarchical cmd_tree
        assert "tune-theme" in cli.commands
        assert "completion" in cli.commands

        # Groups should have hierarchical structure
        tune_theme_group = cli.commands["tune-theme"]
        assert tune_theme_group["type"] == "group"
        assert "increase-adjustment" in tune_theme_group["cmd_tree"]
        assert "decrease-adjustment" in tune_theme_group["cmd_tree"]

        completion_group = cli.commands["completion"]
        assert completion_group["type"] == "group"
        assert "install" in completion_group["cmd_tree"]
        assert "show" in completion_group["cmd_tree"]

    def test_system_tune_theme_methods(self):
        """Test System FreyjaCLI includes TuneTheme methods as hierarchical command groups."""
        cli = FreyjaCLI(System)

        # Check that TuneTheme methods are included as cmd_tree under tune-theme group
        tune_theme_group = cli.commands["tune-theme"]
        expected_commands = [
            "increase-adjustment",
            "decrease-adjustment",
            "select-strategy",
            "toggle-theme",
            "edit-colors",
            "show-rgb",
            "run-interactive",
        ]

        for command in expected_commands:
            assert command in tune_theme_group["cmd_tree"]
            assert tune_theme_group["cmd_tree"][command]["type"] == "command"

    def test_system_completion_methods(self):
        """Test System FreyjaCLI includes Completion methods as hierarchical command groups."""
        cli = FreyjaCLI(System)

        # Check that Completion methods are included as cmd_tree under completion group
        completion_group = cli.commands["completion"]
        expected_commands = ["install", "show"]

        for command in expected_commands:
            assert command in completion_group["cmd_tree"]
            assert completion_group["cmd_tree"][command]["type"] == "command"

    def test_system_cli_execution(self):
        """Test System FreyjaCLI can execute cmd_tree."""
        cli = FreyjaCLI(System)

        # Test that we can create a parser without errors
        parser = cli.create_parser()
        assert parser is not None

        # Test parsing a valid hierarchical command
        args = parser.parse_args(["tune-theme", "toggle-theme"])
        assert hasattr(args, "_cli_function")
        assert args._cli_function is not None


class TestSystemIntegration:
    """Integration tests for System class with FreyjaCLI."""

    def test_system_help_generation(self):
        """Test System FreyjaCLI generates help correctly."""
        cli = FreyjaCLI(System, title="System Test FreyjaCLI")
        parser = cli.create_parser()

        help_text = parser.format_help()

        # Should contain main sections
        assert "System Test FreyjaCLI" in help_text
        assert "tune-theme" in help_text
        assert "completion" in help_text

    def test_system_command_group_help(self):
        """Test System FreyjaCLI command group help generation."""
        cli = FreyjaCLI(System)
        parser = cli.create_parser()

        # Test that parsing to command level works (help would exit)
        with pytest.raises(SystemExit):
            parser.parse_args(["tune-theme", "--help"])


if __name__ == "__main__":
    pytest.main([__file__])
