"""Tests for word expansion logic."""

import pytest
from punmunch.affix import AffixFile, AffixRule, AffixType
from punmunch.dictionary import Dictionary
from punmunch.expander import WordExpander
from punmunch.exceptions import ExpansionError


def create_simple_affix_file():
    """Create a simple test affix file."""
    affix_file = AffixFile()
    
    # Add simple suffix rule: add 's' to most words
    rule_s = AffixRule(flag="S", cross_product=False, strip="", add="s", condition="[^s]")
    affix_file.suffixes["S"] = [rule_s]
    
    # Add suffix rule: change 'y' to 'ies' 
    rule_ies = AffixRule(flag="Y", cross_product=False, strip="y", add="ies", condition="y")
    affix_file.suffixes["Y"] = [rule_ies]
    
    # Add prefix rule: add 'un-'
    rule_un = AffixRule(flag="U", cross_product=True, strip="", add="un", condition=".")
    affix_file.prefixes["U"] = [rule_un]
    
    return affix_file


def create_simple_dictionary():
    """Create a simple test dictionary."""
    dictionary = Dictionary()
    dictionary.add_word("cat", ["S"])
    dictionary.add_word("dog", ["S"])  
    dictionary.add_word("happy", ["S", "Y", "U"])
    dictionary.add_word("try", ["Y"])
    return dictionary


def test_basic_suffix_expansion():
    """Test basic suffix expansion."""
    affix_file = create_simple_affix_file()
    dictionary = create_simple_dictionary()
    expander = WordExpander(affix_file, dictionary)
    
    # Test simple suffix addition
    expanded = expander.expand_word("cat", ["S"])
    assert "cat" in expanded
    assert "cats" in expanded
    
    # Test y to ies transformation
    expanded = expander.expand_word("try", ["Y"])
    assert "try" in expanded
    assert "tries" in expanded


def test_basic_prefix_expansion():
    """Test basic prefix expansion."""
    affix_file = create_simple_affix_file()
    dictionary = create_simple_dictionary()
    expander = WordExpander(affix_file, dictionary)
    
    # Test prefix addition
    expanded = expander.expand_word("happy", ["U"])
    assert "happy" in expanded
    assert "unhappy" in expanded


def test_cross_product_expansion():
    """Test cross-product expansion (prefix + suffix)."""
    affix_file = create_simple_affix_file()
    dictionary = create_simple_dictionary()
    expander = WordExpander(affix_file, dictionary)
    
    # Test cross-product: un- + -s
    expanded = expander.expand_word("happy", ["U", "S"])
    assert "happy" in expanded
    assert "unhappy" in expanded  # prefix only
    assert "happys" in expanded   # suffix only (even though grammatically wrong)
    # Cross-product should be generated since U has cross_product=True


def test_dictionary_word_expansion():
    """Test expansion of dictionary words."""
    affix_file = create_simple_affix_file()
    dictionary = create_simple_dictionary()
    expander = WordExpander(affix_file, dictionary)
    
    # Test expansion using dictionary flags
    expanded = expander.expand_dictionary_word("happy")
    assert "happy" in expanded
    assert "happys" in expanded
    assert "happies" in expanded  # y to ies
    assert "unhappy" in expanded  # prefix


def test_simple_expansion_without_dictionary():
    """Test simple expansion without dictionary validation."""
    affix_file = create_simple_affix_file()
    expander = WordExpander(affix_file, None)
    
    # This should try all possible rules
    expanded = expander.expand_word_simple("test")
    assert "test" in expanded
    assert "tests" in expanded  # Should apply S rule
    # May include other forms depending on which rules match


def test_condition_matching():
    """Test that conditions are properly matched."""
    affix_file = AffixFile()
    
    # Rule that only applies to words ending in consonant
    rule_consonant = AffixRule(flag="C", cross_product=False, strip="", add="ed", condition="[^aeiou]")
    affix_file.suffixes["C"] = [rule_consonant]
    
    expander = WordExpander(affix_file, None)
    
    # Should apply to 'walk' (ends in consonant)
    expanded = expander.expand_word("walk", ["C"])
    assert "walk" in expanded
    assert "walked" in expanded
    
    # Should not apply to 'make' (ends in vowel)
    expanded = expander.expand_word("make", ["C"])
    assert "make" in expanded
    assert "makeed" not in expanded


def test_strip_operations():
    """Test strip operations in rules."""
    affix_file = AffixFile()
    
    # Rule that strips 'e' and adds 'ing'
    rule_ing = AffixRule(flag="I", cross_product=False, strip="e", add="ing", condition="e")
    affix_file.suffixes["I"] = [rule_ing]
    
    expander = WordExpander(affix_file, None)
    
    expanded = expander.expand_word("make", ["I"])
    assert "make" in expanded
    assert "making" in expanded  # Strip 'e', add 'ing'
    assert "makeing" not in expanded


def test_no_affix_file_error():
    """Test error when no affix file is loaded."""
    expander = WordExpander()
    
    with pytest.raises(ExpansionError):
        expander.expand_word("test")
    
    with pytest.raises(ExpansionError):
        expander.expand_word_simple("test")


def test_expand_all_dictionary():
    """Test expanding all words in dictionary."""
    affix_file = create_simple_affix_file()
    dictionary = create_simple_dictionary()
    expander = WordExpander(affix_file, dictionary)
    
    results = expander.expand_all_dictionary()
    
    assert "cat" in results
    assert "dog" in results
    assert "happy" in results
    assert "try" in results
    
    # Check some expansions
    assert "cats" in results["cat"]
    assert "dogs" in results["dog"]
    assert "tries" in results["try"]
    assert "unhappy" in results["happy"]


def test_empty_expansion():
    """Test expansion with no applicable rules."""
    affix_file = AffixFile()
    expander = WordExpander(affix_file, None)
    
    # No rules defined, should just return the original word
    expanded = expander.expand_word_simple("test")
    assert expanded == {"test"}


def test_flag_resolution():
    """Test flag alias resolution."""
    affix_file = AffixFile()
    affix_file.affix_aliases["100"] = ["S", "Y"]
    
    # Add the actual rules
    rule_s = AffixRule(flag="S", cross_product=False, strip="", add="s", condition=".")
    rule_y = AffixRule(flag="Y", cross_product=False, strip="y", add="ies", condition="y")
    affix_file.suffixes["S"] = [rule_s]
    affix_file.suffixes["Y"] = [rule_y]
    
    expander = WordExpander(affix_file, None)
    
    # Test with alias flag
    expanded = expander.expand_word("happy", ["100"])
    assert "happy" in expanded
    assert "happys" in expanded  # S rule
    assert "happies" in expanded  # Y rule


def test_recursion_control():
    """Test that recursion is properly controlled."""
    affix_file = create_simple_affix_file()
    expander = WordExpander(affix_file, None)
    
    # Even with potential for infinite recursion, should terminate
    expanded = expander.expand_word_simple("test")
    assert len(expanded) < 100  # Should not explode to huge number


def test_infinite_loop_prevention():
    """Test prevention of infinite loops in expansion."""
    affix_file = AffixFile()
    
    # Create a rule that could potentially create infinite loops
    rule = AffixRule(flag="L", cross_product=False, strip="", add="", condition=".")
    affix_file.suffixes["L"] = [rule]
    
    expander = WordExpander(affix_file, None)
    
    # Should not create infinite loop
    expanded = expander.expand_word("test", ["L"])
    assert "test" in expanded
    # Should not have duplicate "test" entries or infinite expansion