"""Tests for affix file parsing."""

import pytest
from io import StringIO
from punmunch.affix import AffixFile, AffixRule, AffixType, FlagType
from punmunch.exceptions import AffixFileError


def test_affix_rule_condition_matching():
    """Test affix rule condition matching."""
    # Simple condition
    rule = AffixRule(flag="A", cross_product=False, strip="", add="s", condition=".")
    assert rule.matches_condition("test", AffixType.SUFFIX)
    
    # Character class condition
    rule = AffixRule(flag="B", cross_product=False, strip="", add="ed", condition="[^y]")
    assert rule.matches_condition("walk", AffixType.SUFFIX)
    assert not rule.matches_condition("try", AffixType.SUFFIX)


def test_simple_affix_file_parsing():
    """Test parsing of a simple affix file."""
    affix_content = """
SET UTF-8
TRY esn

PFX A Y 1
PFX A 0 un .

SFX B Y 2
SFX B 0 s [^s]
SFX B 0 es s
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    assert affix_file.encoding == "UTF-8"
    assert affix_file.try_chars == "esn"
    assert "A" in affix_file.prefixes
    assert "B" in affix_file.suffixes
    assert len(affix_file.prefixes["A"]) == 1
    assert len(affix_file.suffixes["B"]) == 2


def test_long_flag_parsing():
    """Test parsing of long flag format."""
    affix_content = """
FLAG long

PFX AB Y 1
PFX AB 0 un .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    assert affix_file.flag_type == FlagType.LONG
    assert "AB" in affix_file.prefixes


def test_flag_parsing_methods():
    """Test different flag parsing methods."""
    affix_file = AffixFile()
    
    # Char flags
    affix_file.flag_type = FlagType.CHAR
    flags = affix_file._parse_flags("ABC")
    assert flags == ["A", "B", "C"]
    
    # Long flags
    affix_file.flag_type = FlagType.LONG
    flags = affix_file._parse_flags("ABCD")
    assert flags == ["AB", "CD"]
    
    # Numeric flags
    affix_file.flag_type = FlagType.NUM
    flags = affix_file._parse_flags("123,456,789")
    assert flags == ["123", "456", "789"]


def test_affix_aliases():
    """Test AF (affix aliases) parsing."""
    affix_content = """
AF TZ # 360

SFX TZ Y 2  
SFX TZ 0 a .
SFX TZ 0 e .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    assert "360" in affix_file.affix_aliases
    assert affix_file.affix_aliases["360"] == ["T", "Z"]


def test_cross_product_flag():
    """Test cross product flag handling."""
    affix_content = """
SFX A Y 1
SFX A 0 s .

PFX B Y 1  
PFX B 0 un .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    suffix_rules = affix_file.get_suffix_rules("A")
    prefix_rules = affix_file.get_prefix_rules("B")
    
    assert len(suffix_rules) == 1
    assert len(prefix_rules) == 1
    assert suffix_rules[0].cross_product == True
    assert prefix_rules[0].cross_product == True


def test_condition_regex_conversion():
    """Test conversion of hunspell conditions to regex."""
    rule = AffixRule(flag="A", cross_product=False, strip="", add="s", condition="[aeiou]")
    assert rule.matches_condition("make", AffixType.SUFFIX)
    assert not rule.matches_condition("try", AffixType.SUFFIX)
    
    rule = AffixRule(flag="B", cross_product=False, strip="", add="ed", condition="[^y]")
    assert rule.matches_condition("walk", AffixType.SUFFIX)
    assert not rule.matches_condition("try", AffixType.SUFFIX)


def test_invalid_affix_file():
    """Test handling of invalid affix files."""
    # Invalid affix definition
    invalid_content = """
PFX A
"""
    
    lines = invalid_content.strip().split('\n')
    affix_file = AffixFile()
    
    with pytest.raises(AffixFileError):
        affix_file._parse_file(lines)


def test_fullstrip_option():
    """Test FULLSTRIP option parsing."""
    affix_content = """
FULLSTRIP

SFX A Y 1
SFX A ing ed .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    assert affix_file.fullstrip == True


def test_get_all_flags():
    """Test getting all defined flags."""
    affix_content = """
PFX A Y 1
PFX A 0 un .

SFX B Y 1
SFX B 0 s .

SFX C Y 1  
SFX C 0 ed .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    all_flags = affix_file.get_all_flags()
    assert all_flags == {"A", "B", "C"}


def test_has_flag():
    """Test flag existence checking."""
    affix_content = """
PFX A Y 1
PFX A 0 un .

SFX B Y 1
SFX B 0 s .
"""
    
    lines = affix_content.strip().split('\n')
    affix_file = AffixFile()
    affix_file._parse_file(lines)
    
    assert affix_file.has_flag("A")
    assert affix_file.has_flag("B")
    assert not affix_file.has_flag("C")


def test_empty_rules():
    """Test handling of empty rule lists."""
    affix_file = AffixFile()
    
    assert affix_file.get_prefix_rules("X") == []
    assert affix_file.get_suffix_rules("Y") == []


def test_strip_and_add_operations():
    """Test strip and add operations in rules."""
    # Rule with no strip (0 means no strip)
    rule = AffixRule(flag="A", cross_product=False, strip="0", add="s", condition=".")
    assert rule.strip == ""  # Should be converted to empty string
    
    # Rule with actual strip
    rule = AffixRule(flag="B", cross_product=False, strip="y", add="ies", condition="y")
    assert rule.strip == "y"
    assert rule.add == "ies"