"""Test which.py builtin command detection and functionality."""

import os
import platform
import sys
from unittest.mock import patch

import pytest

from ..cli import (
    WINDOWS_BUILTINS,
    WindowsBuiltinCommands,
    find_executable,
    main,
)


@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-only test")
def test_windows_builtin_commands():
    """Test that Windows builtin commands are detected correctly."""
    # Test some common builtin commands
    builtin_commands = ["dir", "echo", "cls", "cd", "md", "rd"]

    for cmd in builtin_commands:
        name, path = find_executable(cmd, fuzzy=False)
        assert name == cmd
        assert path is not None
        assert "cmd.exe (built-in)" in path


@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-only test")
def test_regular_executables():
    """Test that regular executables still work."""
    # Test some regular executables that should exist on most Windows systems
    regular_commands = ["cmd", "notepad"]

    for cmd in regular_commands:
        name, path = find_executable(cmd, fuzzy=False)
        assert name == cmd
        assert path is not None
        assert "cmd.exe (built-in)" not in path


def test_nonexistent_command():
    """Test that nonexistent commands return None."""
    name, path = find_executable("nonexistent_command_xyz", fuzzy=False)
    assert name == "nonexistent_command_xyz"
    assert path is None


@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-only test")
def test_fuzzy_matching_with_builtins():
    """Test fuzzy matching works with built-in commands."""
    # This should not find built-ins with fuzzy matching since where/find doesn't support it
    name, _path = find_executable("di", fuzzy=True)  # Should match 'dir'
    # Note: fuzzy matching with built-ins is limited since 'where *di*' won't find built-ins
    # But regular 'where di' won't find anything either
    assert name == "di"
    # Result depends on system - might find something or not


@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-only test")
def test_windows_builtins_class():
    """Test WindowsBuiltinCommands dataclass functionality."""
    builtins = WindowsBuiltinCommands()

    # Test is_builtin method
    assert builtins.is_builtin("dir")
    assert builtins.is_builtin("DIR")  # Case insensitive
    assert builtins.is_builtin("echo")
    assert not builtins.is_builtin("nonexistent")

    # Test commands property is cached
    commands1 = builtins.commands
    commands2 = builtins.commands
    assert commands1 is commands2  # Same object (cached)

    # Test cmd_exe_path is cached
    path1 = builtins.cmd_exe_path
    path2 = builtins.cmd_exe_path
    assert path1 is path2  # Same object (cached)
    assert "cmd.exe (built-in)" in path1


@pytest.mark.skipif(platform.system() != "Windows", reason="Windows-only test")
def test_windows_builtins_global_instance():
    """Test that global WINDOWS_BUILTINS instance works correctly."""
    # Test global instance
    assert WINDOWS_BUILTINS.is_builtin("dir")
    assert WINDOWS_BUILTINS.is_builtin("echo")
    assert "cmd.exe (built-in)" in WINDOWS_BUILTINS.cmd_exe_path

    # Verify it's the same instance
    assert WINDOWS_BUILTINS.commands is WINDOWS_BUILTINS.commands


@patch("pytola.system.which.cli.IS_WINDOWS", False)
def test_unix_system_no_builtin_check():
    """Test that Unix systems don't check Windows built-ins."""
    with patch("pytola.system.which.cli.WINDOWS_BUILTINS") as mock_builtins:
        name, path = find_executable("dir", fuzzy=False)
        # Should not call is_builtin on Unix systems
        mock_builtins.is_builtin.assert_not_called()
        # Should return None for dir on Unix
        assert name == "dir"
        assert path is None


@patch("pytola.system.which.cli.IS_WINDOWS", False)
@patch("pytola.system.which.cli.os.access")
def test_unix_system_usr_bin_path(mock_access):
    """Test Unix system /usr/bin/ path checking (line 166)."""
    mock_access.return_value = True
    name, path = find_executable("custom_cmd", fuzzy=False)
    assert name == "custom_cmd"
    assert path == "/usr/bin/custom_cmd"
    mock_access.assert_called_once_with("/usr/bin/custom_cmd", os.X_OK)


def test_main_function_exists():
    """Test that main function exists and can be imported."""
    assert callable(main)


def test_find_executable_python():
    """Test find_executable with python command."""
    name, path = find_executable("python", fuzzy=False)
    assert name == "python"
    assert path is not None
    # Handle both string and list return types
    if isinstance(path, list):
        # If it's a list, check that at least one path contains 'python'
        assert any("python" in p.lower() for p in path)
    else:
        # If it's a string, check directly
        assert "python" in path.lower()


def test_find_executable_multiple():
    """Test find_executable with multiple commands."""
    # Test python
    name1, path1 = find_executable("python", fuzzy=False)
    assert name1 == "python"
    assert path1 is not None

    # Test pip
    name2, _path2 = find_executable("pip", fuzzy=False)
    assert name2 == "pip"
    # pip might or might not be found depending on environment


def test_main_quiet_mode(capsys):
    """Test main function with quiet mode."""
    test_args = ["which.py", "-q", "python"]
    with patch.object(sys, "argv", test_args):
        main()
    captured = capsys.readouterr()
    # Output goes to stderr due to logging configuration
    output = captured.out + captured.err
    # In quiet mode, should only show path without status symbols
    output_lines = output.strip().split("\n")
    assert len(output_lines) >= 1
    # Should not contain status symbols
    assert "✓" not in output
    assert "✗" not in output


def test_find_executable_fuzzy():
    """Test find_executable with fuzzy matching."""
    name, _path = find_executable("pyth", fuzzy=True)
    assert name == "pyth"
    # Result depends on system - might find python-related executables


def test_main_combined_flags(capsys):
    """Test main function with both quiet and fuzzy flags."""
    test_args = ["which.py", "-q", "-f", "pyth"]
    with patch.object(sys, "argv", test_args):
        main()
    captured = capsys.readouterr()
    # Should work without errors
    output = captured.out + captured.err
    assert "Error" not in output


def test_main_logging_patterns_indirectly():
    """Test main function logic indirectly (since logging capture is problematic)."""
    # Instead of testing the actual output, test the logic that generates it

    # Test that found commands would generate success logging (lines 194-195)
    name, path = find_executable("python", fuzzy=False)
    assert name == "python"
    assert path is not None
    # The logging "✓ {name} -> {path}" would be generated

    # Test that not found commands would generate failure logging (lines 196-197)
    name, path = find_executable("nonexistent12345", fuzzy=False)
    assert name == "nonexistent12345"
    assert path is None
    # The logging "✗ {name} -> not found" would be generated

    # Test that multiple commands trigger summary (line 200)
    # This is tested by the existing test_main_with_multiple_commands test
    # which covers the logic path that leads to the summary output


def test_main_no_arguments_shows_help():
    """Test that main function shows help when no arguments provided."""
    test_args = ["which.py"]
    with patch.object(sys, "argv", test_args):
        with pytest.raises(SystemExit) as exc_info:
            main()
        assert exc_info.value.code != 0  # Should exit with error


def test_main_help_flag(capsys):
    """Test that help flag works correctly."""
    test_args = ["which.py", "-h"]
    with patch.object(sys, "argv", test_args):
        with pytest.raises(SystemExit) as exc_info:
            main()
        assert exc_info.value.code == 0  # Help should exit cleanly
    captured = capsys.readouterr()
    assert "usage:" in captured.out.lower() or "help" in captured.out.lower()


def test_find_executable_invalid():
    """Test find_executable with invalid command."""
    name, path = find_executable("this_command_definitely_does_not_exist_12345", fuzzy=False)
    assert name == "this_command_definitely_does_not_exist_12345"
    assert path is None


def test_find_executable_mixed():
    """Test find_executable with mix of found and not found commands."""
    # Valid command
    name1, path1 = find_executable("python", fuzzy=False)
    assert name1 == "python"
    assert path1 is not None

    # Invalid command
    name2, path2 = find_executable("invalid_cmd_12345", fuzzy=False)
    assert name2 == "invalid_cmd_12345"
    assert path2 is None
