"""Tests for CLI module."""

from unittest.mock import MagicMock, patch

from click.testing import CliRunner

from voicemqtt.cli import main, VERSION


class TestCLI:
    """Tests for CLI."""
    
    def test_version_flag(self):
        """Test --version flag."""
        runner = CliRunner()
        result = runner.invoke(main, ["--version"])
        
        assert result.exit_code == 0
        assert VERSION in result.output
    
    def test_help_flag(self):
        """Test --help flag."""
        runner = CliRunner()
        result = runner.invoke(main, ["--help"])

        assert result.exit_code == 0
        assert "VoiceMQTT" in result.output
        assert "--mqtt-host" in result.output
        assert "--mqtt-port" in result.output
        assert "--model" in result.output
    
    @patch("voicemqtt.cli.MQTTActivator")
    @patch("voicemqtt.cli.AudioRecorder")
    @patch("voicemqtt.cli.Transcriber")
    @patch("voicemqtt.cli.ClipboardManager")
    def test_successful_run_single_mode(self, mock_clipboard, mock_transcriber, mock_recorder, mock_mqtt):
        """Test successful run in single mode."""
        # Setup mocks
        mock_mqtt_instance = MagicMock()
        mock_mqtt_instance.connect.return_value = True
        mock_mqtt_instance.wait_for_activation.return_value = True
        mock_mqtt.return_value = mock_mqtt_instance
        
        mock_recorder_instance = MagicMock()
        mock_recorder_instance.record.return_value = MagicMock()  # Non-None audio
        mock_recorder.return_value = mock_recorder_instance
        
        mock_transcriber_instance = MagicMock()
        mock_transcriber_instance.transcribe.return_value = "Hello World"
        mock_transcriber.return_value = mock_transcriber_instance
        
        mock_clipboard_instance = MagicMock()
        mock_clipboard_instance.copy_text.return_value = True
        mock_clipboard.return_value = mock_clipboard_instance
        
        runner = CliRunner()
        result = runner.invoke(main, ["--single"])
        
        assert result.exit_code == 0
        mock_mqtt_instance.connect.assert_called_once()
        mock_mqtt_instance.wait_for_activation.assert_called_once()
        mock_recorder_instance.record.assert_called_once()
        mock_transcriber_instance.transcribe.assert_called_once()
        mock_clipboard_instance.copy_text.assert_called_once_with("Hello World")
    
    @patch("voicemqtt.cli.MQTTActivator")
    def test_mqtt_connection_failure(self, mock_mqtt):
        """Test handling of MQTT connection failure."""
        mock_mqtt_instance = MagicMock()
        mock_mqtt_instance.connect.return_value = False
        mock_mqtt.return_value = mock_mqtt_instance
        
        runner = CliRunner()
        result = runner.invoke(main, ["--single"])
        
        assert result.exit_code == 1
        mock_mqtt_instance.connect.assert_called_once()
    
    @patch("voicemqtt.cli.MQTTActivator")
    @patch("voicemqtt.cli.AudioRecorder")
    @patch("voicemqtt.cli.Transcriber")
    @patch("voicemqtt.cli.ClipboardManager")
    def test_no_audio_recorded(self, mock_clipboard, mock_transcriber, mock_recorder, mock_mqtt):
        """Test when no audio is recorded."""
        mock_mqtt_instance = MagicMock()
        mock_mqtt_instance.connect.return_value = True
        mock_mqtt_instance.wait_for_activation.return_value = True
        mock_mqtt.return_value = mock_mqtt_instance
        
        mock_recorder_instance = MagicMock()
        mock_recorder_instance.record.return_value = None  # No audio
        mock_recorder.return_value = mock_recorder_instance
        
        runner = CliRunner()
        result = runner.invoke(main, ["--single"])
        
        assert result.exit_code == 0
        mock_transcriber.return_value.transcribe.assert_not_called()
    
    @patch("voicemqtt.cli.MQTTActivator")
    @patch("voicemqtt.cli.AudioRecorder")
    @patch("voicemqtt.cli.Transcriber")
    @patch("voicemqtt.cli.ClipboardManager")
    def test_empty_transcript(self, mock_clipboard, mock_transcriber, mock_recorder, mock_mqtt):
        """Test when transcript is empty."""
        mock_mqtt_instance = MagicMock()
        mock_mqtt_instance.connect.return_value = True
        mock_mqtt_instance.wait_for_activation.return_value = True
        mock_mqtt.return_value = mock_mqtt_instance
        
        mock_recorder_instance = MagicMock()
        mock_recorder_instance.record.return_value = MagicMock()
        mock_recorder.return_value = mock_recorder_instance
        
        mock_transcriber_instance = MagicMock()
        mock_transcriber_instance.transcribe.return_value = ""  # Empty transcript
        mock_transcriber.return_value = mock_transcriber_instance
        
        mock_clipboard_instance = MagicMock()
        mock_clipboard.return_value = mock_clipboard_instance
        
        runner = CliRunner()
        result = runner.invoke(main, ["--single"])
        
        assert result.exit_code == 0
        mock_clipboard_instance.copy_text.assert_not_called()
    
    @patch("voicemqtt.cli.MQTTActivator")
    def test_keyboard_interrupt(self, mock_mqtt):
        """Test handling of keyboard interrupt."""
        mock_mqtt_instance = MagicMock()
        mock_mqtt_instance.connect.return_value = True
        mock_mqtt_instance.wait_for_activation.side_effect = KeyboardInterrupt()
        mock_mqtt.return_value = mock_mqtt_instance

        runner = CliRunner()
        result = runner.invoke(main)

        assert result.exit_code == 0  # Should exit gracefully
        mock_mqtt_instance.disconnect.assert_called_once()

    @patch("voicemqtt.cli.AudioRecorder")
    def test_calibrate_mode(self, mock_recorder):
        """Test calibration mode."""
        mock_recorder_instance = MagicMock()
        mock_recorder_instance.calibrate_silence.return_value = 0.005
        mock_recorder.return_value = mock_recorder_instance

        runner = CliRunner()
        result = runner.invoke(main, ["--calibrate"])

        assert result.exit_code == 0
        mock_recorder_instance.calibrate_silence.assert_called_once()

    @patch("voicemqtt.cli.AudioRecorder")
    def test_calibrate_mode_failure(self, mock_recorder):
        """Test calibration mode when calibration fails."""
        mock_recorder_instance = MagicMock()
        mock_recorder_instance.calibrate_silence.return_value = None
        mock_recorder.return_value = mock_recorder_instance

        runner = CliRunner()
        result = runner.invoke(main, ["--calibrate"])

        assert result.exit_code == 1
        mock_recorder_instance.calibrate_silence.assert_called_once()
