"""Tests for command-line interface."""

import pytest
import subprocess
import sys
from pathlib import Path
from unittest.mock import patch, MagicMock
from io import StringIO

from punmunch.cli import main, read_words_from_stdin, write_words_to_stdout


def create_test_files(tmp_path):
    """Create test affix and dictionary files."""
    aff_content = """SET UTF-8
PFX U Y 1
PFX U 0 un .

SFX S Y 1
SFX S 0 s [^s]
"""
    
    dic_content = """2
cat/S
happy/SU
"""
    
    aff_file = tmp_path / "test.aff"
    dic_file = tmp_path / "test.dic"
    
    aff_file.write_text(aff_content)
    dic_file.write_text(dic_content)
    
    return str(aff_file), str(dic_file)


def test_read_words_from_stdin():
    """Test reading words from stdin."""
    test_input = "word1\nword2\n\nword3\n"
    
    with patch('sys.stdin', StringIO(test_input)):
        words = read_words_from_stdin()
        assert words == ["word1", "word2", "word3"]


def test_write_words_to_stdout(capsys):
    """Test writing words to stdout."""
    words = ["word1", "word2", "word3"]
    write_words_to_stdout(words)
    
    captured = capsys.readouterr()
    assert captured.out == "word1\nword2\nword3\n"


def test_cli_help():
    """Test CLI help output."""
    with patch('sys.argv', ['punmunch', '--help']):
        with pytest.raises(SystemExit) as exc_info:
            main()
        assert exc_info.value.code == 0


def test_cli_version():
    """Test CLI version output."""
    with patch('sys.argv', ['punmunch', '--version']):
        with pytest.raises(SystemExit) as exc_info:
            main()
        assert exc_info.value.code == 0


def test_cli_missing_files():
    """Test CLI with missing files."""
    # Missing affix file
    with patch('sys.argv', ['punmunch', 'nonexistent.aff', 'nonexistent.dic']):
        with patch('sys.stderr', StringIO()) as mock_stderr:
            with pytest.raises(SystemExit) as exc_info:
                main()
            assert exc_info.value.code == 1
            assert "not found" in mock_stderr.getvalue()


def test_cli_missing_dictionary():
    """Test CLI without dictionary file when not in expand mode."""
    with patch('sys.argv', ['punmunch', 'test.aff']):
        with patch('sys.stderr', StringIO()) as mock_stderr:
            with pytest.raises(SystemExit) as exc_info:
                main()
            assert exc_info.value.code == 1
            assert "required unless using --expand" in mock_stderr.getvalue()


def test_cli_full_unmunch(tmp_path):
    """Test full unmunch mode via CLI."""
    aff_file, dic_file = create_test_files(tmp_path)
    
    with patch('sys.argv', ['punmunch', aff_file, dic_file]):
        with patch('sys.stdout', StringIO()) as mock_stdout:
            with patch('sys.stderr', StringIO()):
                main()
        
        output = mock_stdout.getvalue()
        assert "cat" in output
        assert "cats" in output
        assert "happy" in output
        assert "unhappy" in output


def test_cli_expand_mode(tmp_path):
    """Test expand mode via CLI."""
    aff_file, dic_file = create_test_files(tmp_path)
    test_input = "cat\nhappy\n"
    
    with patch('sys.argv', ['punmunch', '--expand', aff_file]):
        with patch('sys.stdin', StringIO(test_input)):
            with patch('sys.stdout', StringIO()) as mock_stdout:
                with patch('sys.stderr', StringIO()):
                    main()
        
        output = mock_stdout.getvalue()
        assert "cat" in output
        assert "happy" in output
        # Should contain various expanded forms


def test_cli_expand_with_dictionary(tmp_path):
    """Test expand mode with dictionary validation."""
    aff_file, dic_file = create_test_files(tmp_path)
    test_input = "cat\nhappy\n"
    
    with patch('sys.argv', ['punmunch', '--expand', '--validate', aff_file, dic_file]):
        with patch('sys.stdin', StringIO(test_input)):
            with patch('sys.stdout', StringIO()) as mock_stdout:
                with patch('sys.stderr', StringIO()):
                    main()
        
        output = mock_stdout.getvalue()
        assert "cat" in output
        assert "cats" in output
        assert "happy" in output
        assert "unhappy" in output


def test_cli_stats_mode(tmp_path):
    """Test stats mode via CLI."""
    aff_file, dic_file = create_test_files(tmp_path)
    
    with patch('sys.argv', ['punmunch', '--stats', aff_file, dic_file]):
        with patch('sys.stderr', StringIO()) as mock_stderr:
            main()
        
        output = mock_stderr.getvalue()
        assert "Statistics:" in output
        assert "Flag type:" in output
        assert "Dictionary words:" in output


def test_cli_stats_with_expand(tmp_path):
    """Test stats mode combined with expand."""
    aff_file, dic_file = create_test_files(tmp_path)
    test_input = "cat\n"
    
    with patch('sys.argv', ['punmunch', '--stats', '--expand', aff_file, dic_file]):
        with patch('sys.stdin', StringIO(test_input)):
            with patch('sys.stdout', StringIO()) as mock_stdout:
                with patch('sys.stderr', StringIO()) as mock_stderr:
                    main()
        
        stderr_output = mock_stderr.getvalue()
        stdout_output = mock_stdout.getvalue()
        
        # Should show stats
        assert "Statistics:" in stderr_output
        # Should also do expansion
        assert "cat" in stdout_output


def test_cli_empty_stdin(tmp_path):
    """Test CLI with empty stdin in expand mode."""
    aff_file, dic_file = create_test_files(tmp_path)
    
    with patch('sys.argv', ['punmunch', '--expand', aff_file]):
        with patch('sys.stdin', StringIO("")):
            with patch('sys.stderr', StringIO()) as mock_stderr:
                main()
        
        output = mock_stderr.getvalue()
        assert "No words provided" in output


def test_cli_keyboard_interrupt(tmp_path):
    """Test CLI handling of keyboard interrupt."""
    aff_file, dic_file = create_test_files(tmp_path)
    
    with patch('sys.argv', ['punmunch', '--expand', aff_file]):
        with patch('sys.stdin', StringIO("test\n")):
            with patch('punmunch.cli.read_words_from_stdin', side_effect=KeyboardInterrupt):
                with patch('sys.stderr', StringIO()) as mock_stderr:
                    with pytest.raises(SystemExit) as exc_info:
                        main()
                    assert exc_info.value.code == 1
                    assert "Interrupted" in mock_stderr.getvalue()


def test_cli_broken_pipe():
    """Test CLI handling of broken pipe."""
    words = ["test1", "test2", "test3"]
    
    with patch('builtins.print', side_effect=BrokenPipeError):
        with patch('sys.stderr'):
            with pytest.raises(SystemExit) as exc_info:
                write_words_to_stdout(words)
            assert exc_info.value.code == 0


def test_cli_punmunch_error(tmp_path):
    """Test CLI handling of PunmunchError."""
    # Create invalid affix file
    aff_file = tmp_path / "invalid.aff"
    aff_file.write_text("INVALID CONTENT")
    
    with patch('sys.argv', ['punmunch', '--expand', str(aff_file)]):
        with patch('sys.stdin', StringIO("test\n")):
            with patch('sys.stderr', StringIO()) as mock_stderr:
                with pytest.raises(SystemExit) as exc_info:
                    main()
                assert exc_info.value.code == 1
                assert "Error:" in mock_stderr.getvalue()


def test_cli_unexpected_error(tmp_path):
    """Test CLI handling of unexpected errors."""
    aff_file, dic_file = create_test_files(tmp_path)
    
    with patch('sys.argv', ['punmunch', aff_file, dic_file]):
        with patch('punmunch.unmunch.Punmunch.unmunch_all', side_effect=RuntimeError("Unexpected")):
            with patch('sys.stderr', StringIO()) as mock_stderr:
                with pytest.raises(SystemExit) as exc_info:
                    main()
                assert exc_info.value.code == 1
                assert "Unexpected error:" in mock_stderr.getvalue()