"""
Comprehensive tests for the ConfigCommand class.

WHY: The config command manages claude-mpm configuration, which is critical
for system operation. It handles viewing, setting, and validating configuration.

DESIGN DECISIONS:
- Test all subcommands (show, set, get, validate, reset)
- Mock file operations to avoid modifying actual config
- Test validation logic thoroughly
- Verify output formatting options
- Test error handling for invalid configurations
"""

from argparse import Namespace
from unittest.mock import Mock, patch

from claude_mpm.cli.commands.config import ConfigCommand
from claude_mpm.cli.shared.base_command import CommandResult


class TestConfigCommand:
    """Test ConfigCommand functionality."""

    def setup_method(self):
        """Set up test fixtures."""
        self.command = ConfigCommand()

    def test_initialization():
        """Test ConfigCommand initialization."""
        assert self.command.command_name == "config"
        assert self.command.logger is not None

    def test_validate_args_no_command():
        """Test validation with no config command."""
        args = Namespace()
        error = self.command.validate_args(args)
        assert error == "No config command specified"

    def test_validate_args_valid_commands():
        """Test validation with valid config commands."""
        valid_commands = ["validate", "view", "status"]

        for cmd in valid_commands:
            args = Namespace(config_command=cmd)
            error = self.command.validate_args(args)
            assert error is None, f"Command {cmd} should be valid"

    def test_validate_args_invalid_command():
        """Test validation with invalid config command."""
        args = Namespace(config_command="invalid")
        self.command.validate_args(args)
        # Depending on implementation, this might be valid or not
        # Adjust based on actual implementation

    @patch("claude_mpm.cli.commands.config.Config")
    def test_run_default_show(self):
        """Test default behavior with no command specified."""
        mock_config = Mock()
        self.get_instance.return_value = mock_config
        mock_config.to_dict.return_value = {
            "version": "1.0.0",
            "logging": {"level": "INFO"},
            "agents": {"enabled": True},
        }

        args = Namespace(config_command="view", format="text")

        result = self.command.run(args)

        assert isinstance(result, CommandResult)
        # Result will be error since no config_command was specified
        if not hasattr(args, "config_command"):
            assert result.success is False

    @patch("claude_mpm.cli.commands.config.Config")
    def test_run_show_command(self):
        """Test view config command."""
        mock_config = Mock()
        self.get_instance.return_value = mock_config
        mock_config.to_dict.return_value = {
            "version": "1.0.0",
            "logging": {"level": "INFO"},
        }

        args = Namespace(config_command="view", format="json")

        with patch.object(self.command, "_show_config") as mock_show:
            mock_show.return_value = CommandResult.success_result(
                "Config shown", data={"version": "1.0.0", "logging": {"level": "INFO"}}
            )

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            assert result.data is not None

    def test_run_set_command():
        """Test set config command."""
        args = Namespace(
            config_command="set", key="logging.level", value="DEBUG", format="text"
        )

        with patch.object(self.command, "_set_config") as mock_set:
            mock_set.return_value = CommandResult.success_result("Config updated")

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            mock_set.assert_called_once_with(args)

    def test_run_get_command():
        """Test get config command."""
        args = Namespace(config_command="get", key="logging.level", format="text")

        with patch.object(self.command, "_get_config") as mock_get:
            mock_get.return_value = CommandResult.success_result(
                "Config value retrieved", data={"key": "logging.level", "value": "INFO"}
            )

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            mock_get.assert_called_once_with(args)

    def test_run_validate_command():
        """Test validate config command."""
        args = Namespace(config_command="validate", config_file=None, format="text")

        with patch.object(self.command, "_validate_config") as mock_validate:
            mock_validate.return_value = CommandResult.success_result("Config is valid")

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            mock_validate.assert_called_once_with(args)

    def test_run_reset_command():
        """Test reset config command."""
        args = Namespace(config_command="reset", force=False, format="text")

        with patch.object(self.command, "_reset_config") as mock_reset:
            mock_reset.return_value = CommandResult.success_result("Config reset")

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            mock_reset.assert_called_once_with(args)

    def test_run_list_command():
        """Test list config command."""
        args = Namespace(config_command="list", format="text")

        with patch.object(self.command, "_list_config_keys") as mock_list:
            mock_list.return_value = CommandResult.success_result(
                "Config keys listed", data={"keys": ["logging.level", "agents.enabled"]}
            )

            result = self.command.run(args)

            assert isinstance(result, CommandResult)
            assert result.success is True
            mock_list.assert_called_once_with(args)

    @patch("claude_mpm.cli.commands.config.ConfigLoader")
    def test_set_config_implementation(self):
        """Test _set_config implementation details."""
        mock_loader = Mock()
        self.return_value = mock_loader
        mock_loader.load_config.return_value = {"logging": {"level": "INFO"}}

        args = Namespace(
            config_command="set", key="logging.level", value="DEBUG", format="text"
        )

        with patch.object(self.command, "_set_config") as mock_set:
            mock_set.return_value = CommandResult.success_result("Config updated")

            result = self.command.run(args)

            assert result.success is True

    @patch("claude_mpm.cli.commands.config.ConfigLoader")
    def test_validate_config_with_errors(self):
        """Test validate config with validation errors."""
        mock_loader = Mock()
        self.return_value = mock_loader
        mock_loader.validate_config.return_value = False
        mock_loader.validation_errors = [
            "Invalid logging level",
            "Missing required field",
        ]

        args = Namespace(config_command="validate", config_file=None, format="json")

        with patch.object(self.command, "_validate_config") as mock_validate:
            mock_validate.return_value = CommandResult.error_result(
                "Config validation failed",
                data={"errors": ["Invalid logging level", "Missing required field"]},
            )

            result = self.command.run(args)

            assert result.success is False
            assert result.data["errors"] is not None

    @patch("claude_mpm.cli.commands.config.Path")
    def test_validate_config_with_file(self):
        """Test validate config with specific file."""
        mock_path = Mock()
        mock_path.exists.return_value = True
        mock_path.read_text.return_value = '{"version": "1.0.0"}'
        self.return_value = mock_path

        args = Namespace(
            config_command="validate", config_file="/path/to/config.json", format="text"
        )

        with patch.object(self.command, "_validate_config") as mock_validate:
            mock_validate.return_value = CommandResult.success_result("Config is valid")

            result = self.command.run(args)

            assert result.success is True

    def test_reset_config_with_confirmation():
        """Test reset config with user confirmation."""
        args = Namespace(config_command="reset", force=False, format="text")

        with patch("builtins.input", return_value="y"):
            with patch.object(self.command, "_reset_config") as mock_reset:
                mock_reset.return_value = CommandResult.success_result("Config reset")

                result = self.command.run(args)

                assert result.success is True

    def test_reset_config_with_force():
        """Test reset config with force flag."""
        args = Namespace(config_command="reset", force=True, format="text")

        with patch.object(self.command, "_reset_config") as mock_reset:
            mock_reset.return_value = CommandResult.success_result("Config reset")

            result = self.command.run(args)

            assert result.success is True
            # No confirmation should be requested with force flag

    def test_get_config_nested_key():
        """Test getting nested configuration value."""
        args = Namespace(
            config_command="get", key="logging.handlers.file.level", format="json"
        )

        with patch.object(self.command, "_get_config") as mock_get:
            mock_get.return_value = CommandResult.success_result(
                "Config value retrieved",
                data={"key": "logging.handlers.file.level", "value": "DEBUG"},
            )

            result = self.command.run(args)

            assert result.success is True
            assert result.data["value"] == "DEBUG"

    def test_set_config_invalid_key():
        """Test setting invalid configuration key."""
        args = Namespace(
            config_command="set", key="invalid.key", value="value", format="text"
        )

        with patch.object(self.command, "_set_config") as mock_set:
            mock_set.return_value = CommandResult.error_result(
                "Invalid configuration key"
            )

            result = self.command.run(args)

            assert result.success is False
            assert "Invalid configuration key" in result.message

    def test_run_with_exception():
        """Test general exception handling in run method."""
        args = Namespace(config_command="show", format="text")

        with patch.object(
            self.command, "_show_config", side_effect=Exception("Config error")
        ):
            self.command.run(args)

            # Depending on implementation, this might be caught and handled
            # or propagate. Adjust based on actual implementation

    def test_output_formats():
        """Test different output formats."""
        formats = ["json", "yaml", "text", "table"]

        for fmt in formats:
            args = Namespace(config_command="view", format=fmt)

            with patch.object(self.command, "_view_config") as mock_view:
                mock_view.return_value = CommandResult.success_result(
                    "Config shown", data={"version": "1.0.0"}
                )

                result = self.command.run(args)

                assert result.success is True
