"""Tests for command functionality (set of callables)."""

import pytest

from aap.core import autoarg


def test_commands_basic():
    """Test commands (set) with basic subcommand routing."""
    def add(a: int, b: int):
        """Add two numbers.
        
        Args:
            a: First number
            b: Second number
        """
        return a + b
    
    def multiply(a: int, b: int):
        """Multiply two numbers.
        
        Args:
            a: First number
            b: Second number
        """
        return a * b
    
    wrapped = autoarg({add, multiply})
    
    # Test add command
    result1 = wrapped(['add', '--a', '5', '--b', '3'])
    assert result1 == 8
    
    # Test multiply command
    result2 = wrapped(['multiply', '--a', '5', '--b', '3'])
    assert result2 == 15


def test_commands_different_params():
    """Test commands with different parameter sets."""
    def greet(name: str):
        """Greet someone.
        
        Args:
            name: Person's name
        """
        return f"Hello {name}"
    
    def calculate(x: int, y: int, operation: str = "add"):
        """Perform a calculation.
        
        Args:
            x: First number
            y: Second number
            operation: Operation to perform
        """
        if operation == "add":
            return x + y
        elif operation == "multiply":
            return x * y
        return 0
    
    wrapped = autoarg({greet, calculate})
    
    # Test greet
    result1 = wrapped(['greet', '--name', 'Alice'])
    assert result1 == "Hello Alice"
    
    # Test calculate with default
    result2 = wrapped(['calculate', '--x', '10', '--y', '5'])
    assert result2 == 15
    
    # Test calculate with custom operation
    result3 = wrapped(['calculate', '--x', '10', '--y', '5', '--operation', 'multiply'])
    assert result3 == 50


def test_commands_with_bool_flags():
    """Test commands with boolean flags."""
    def process(name: str, verbose: bool = False):
        """Process something.
        
        Args:
            name: Item name
            verbose: Enable verbose output
        """
        if verbose:
            return f"Processing {name} verbosely"
        return f"Processing {name}"
    
    def cleanup(path: str, force: bool = False):
        """Clean up files.
        
        Args:
            path: Path to clean
            force: Force cleanup
        """
        if force:
            return f"Force cleaning {path}"
        return f"Cleaning {path}"
    
    wrapped = autoarg({process, cleanup})
    
    # Test process without flag
    result1 = wrapped(['process', '--name', 'test'])
    assert result1 == "Processing test"
    
    # Test process with flag
    result2 = wrapped(['process', '--name', 'test', '--verbose'])
    assert result2 == "Processing test verbosely"
    
    # Test cleanup with force
    result3 = wrapped(['cleanup', '--path', '/tmp', '--force'])
    assert result3 == "Force cleaning /tmp"


def test_commands_single_function():
    """Test commands with single function in set."""
    def greet(name: str):
        """Greet someone.
        
        Args:
            name: The name
        """
        return f"Hello {name}"
    
    wrapped = autoarg({greet})
    result = wrapped(['greet', '--name', 'Alice'])
    
    assert result == "Hello Alice"


def test_commands_with_optional_params():
    """Test commands with optional parameters."""
    from typing import Optional
    
    def cmd1(name: str, title: Optional[str] = None):
        """First command.
        
        Args:
            name: Person's name
            title: Optional title
        """
        if title:
            return f"{title} {name}"
        return name
    
    def cmd2(value: int, multiplier: Optional[int] = None):
        """Second command.
        
        Args:
            value: Base value
            multiplier: Optional multiplier
        """
        if multiplier:
            return value * multiplier
        return value
    
    wrapped = autoarg({cmd1, cmd2})
    
    # Test cmd1 without optional
    result1 = wrapped(['cmd1', '--name', 'Smith'])
    assert result1 == "Smith"
    
    # Test cmd1 with optional
    result2 = wrapped(['cmd1', '--name', 'Smith', '--title', 'Dr.'])
    assert result2 == "Dr. Smith"
    
    # Test cmd2 without optional
    result3 = wrapped(['cmd2', '--value', '10'])
    assert result3 == 10
    
    # Test cmd2 with optional
    result4 = wrapped(['cmd2', '--value', '10', '--multiplier', '5'])
    assert result4 == 50


def test_commands_return_type_ignored():
    """Test that return_type parameter is ignored for commands (set)."""
    def func1(x: int):
        """First function.
        
        Args:
            x: A value
        """
        return x * 2
    
    def func2(y: int):
        """Second function.
        
        Args:
            y: A value
        """
        return y * 3
    
    # return_type should be ignored for set
    wrapped = autoarg({func1, func2}, return_type="list")
    
    # Should still work as commands, not sequence
    result1 = wrapped(['func1', '--x', '5'])
    assert result1 == 10
    
    result2 = wrapped(['func2', '--y', '5'])
    assert result2 == 15
