"""Tests for AnsiString ANSI-aware alignment functionality."""

from freyja.utils import AnsiString


class TestStripAnsiCodes:
    """Test ANSI escape code removal functionality."""

    def test_strip_basic_ansi_codes(self):
        """Test removing basic ANSI color codes."""
        # Red text with reset
        colored_text = "\x1b[31mRed\x1b[0m"
        result = AnsiString.strip_ansi_codes(colored_text)
        assert result == "Red"

    def test_strip_complex_ansi_codes(self):
        """Test removing complex ANSI sequences."""
        # Bold red background with blue foreground
        colored_text = "\x1b[1;41;34mComplex\x1b[0m"
        result = AnsiString.strip_ansi_codes(colored_text)
        assert result == "Complex"

    def test_strip_256_color_codes(self):
        """Test removing 256-color ANSI sequences."""
        # 256-color foreground and background
        colored_text = "\x1b[38;5;196mText\x1b[48;5;21m\x1b[0m"
        result = AnsiString.strip_ansi_codes(colored_text)
        assert result == "Text"

    def test_strip_rgb_color_codes(self):
        """Test removing RGB ANSI sequences."""
        # RGB color codes
        colored_text = "\x1b[38;2;255;0;0mRGB\x1b[0m"
        result = AnsiString.strip_ansi_codes(colored_text)
        assert result == "RGB"

    def test_strip_empty_string(self):
        """Test stripping ANSI codes from empty string."""
        assert AnsiString.strip_ansi_codes("") == ""

    def test_strip_none_input(self):
        """Test stripping ANSI codes from None."""
        assert AnsiString.strip_ansi_codes(None) == ""

    def test_strip_no_ansi_codes(self):
        """Test text without ANSI codes remains unchanged."""
        plain_text = "Plain text"
        assert AnsiString.strip_ansi_codes(plain_text) == plain_text

    def test_strip_mixed_content(self):
        """Test text with mixed ANSI codes and plain text."""
        mixed_text = "Start \x1b[31mred\x1b[0m middle \x1b[32mgreen\x1b[0m end"
        result = AnsiString.strip_ansi_codes(mixed_text)
        assert result == "Start red middle green end"


class TestAnsiStringBasic:
    """Test basic AnsiString functionality."""

    def test_init_with_string(self):
        """Test initialization with regular string."""
        ansi_str = AnsiString("Hello")
        assert ansi_str.text == "Hello"
        assert ansi_str.visible_text == "Hello"

    def test_init_with_ansi_string(self):
        """Test initialization with ANSI-coded string."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        assert ansi_str.text == colored_text
        assert ansi_str.visible_text == "Red"

    def test_init_with_none(self):
        """Test initialization with None."""
        ansi_str = AnsiString(None)
        assert ansi_str.text == ""
        assert ansi_str.visible_text == ""

    def test_str_method(self):
        """Test __str__ returns original text with ANSI codes."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        assert str(ansi_str) == colored_text

    def test_repr_method(self):
        """Test __repr__ provides debug representation."""
        ansi_str = AnsiString("test")
        assert repr(ansi_str) == "AnsiString('test')"

    def test_len_method(self):
        """Test __len__ returns visible character count."""
        colored_text = "\x1b[31mRed\x1b[0m"  # 3 visible chars
        ansi_str = AnsiString(colored_text)
        assert len(ansi_str) == 3

    def test_visible_length_property(self):
        """Test visible_length property."""
        colored_text = "\x1b[31mHello\x1b[0m"  # 5 visible chars
        ansi_str = AnsiString(colored_text)
        assert ansi_str.visible_length == 5


class TestAnsiStringAlignment:
    """Test AnsiString format alignment functionality."""

    def test_left_alignment(self):
        """Test left alignment with < specifier."""
        colored_text = "\x1b[31mRed\x1b[0m"  # 3 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:<10}"
        expected = colored_text + "       "  # 7 spaces to reach width 10
        assert result == expected

    def test_right_alignment(self):
        """Test right alignment with > specifier."""
        colored_text = "\x1b[31mRed\x1b[0m"  # 3 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:>10}"
        expected = "       " + colored_text  # 7 spaces before text
        assert result == expected

    def test_center_alignment(self):
        """Test center alignment with ^ specifier."""
        colored_text = "\x1b[31mRed\x1b[0m"  # 3 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:^10}"
        expected = "   " + colored_text + "    "  # 3 + 4 spaces around text
        assert result == expected

    def test_center_alignment_odd_padding(self):
        """Test center alignment with odd padding distribution."""
        colored_text = "\x1b[31mTest\x1b[0m"  # 4 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:^9}"
        expected = "  " + colored_text + "   "  # 2 + 3 spaces (left gets less)
        assert result == expected

    def test_sign_aware_alignment(self):
        """Test = alignment (treated as right alignment for text)."""
        colored_text = "\x1b[31mText\x1b[0m"  # 4 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:=10}"
        expected = "      " + colored_text  # 6 spaces before text
        assert result == expected


class TestAnsiStringFillCharacters:
    """Test AnsiString with custom fill characters."""

    def test_custom_fill_left_align(self):
        """Test left alignment with custom fill character."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:*<8}"
        expected = colored_text + "*****"  # Fill with asterisks
        assert result == expected

    def test_custom_fill_right_align(self):
        """Test right alignment with custom fill character."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:->8}"
        expected = "-----" + colored_text  # Fill with dashes
        assert result == expected

    def test_custom_fill_center_align(self):
        """Test center alignment with custom fill character."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:.^9}"
        expected = "..." + colored_text + "..."  # Fill with dots
        assert result == expected


class TestAnsiStringEdgeCases:
    """Test AnsiString edge cases and error handling."""

    def test_no_format_spec(self):
        """Test formatting with empty format spec."""
        colored_text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str}"
        assert result == colored_text

    def test_width_smaller_than_text(self):
        """Test when requested width is smaller than text length."""
        colored_text = "\x1b[31mLongText\x1b[0m"  # 8 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:<5}"  # Width 5, but text is 8 chars
        assert result == colored_text  # Should return original text

    def test_width_equal_to_text(self):
        """Test when requested width equals text length."""
        colored_text = "\x1b[31mTest\x1b[0m"  # 4 visible chars
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:<4}"  # Exact width
        assert result == colored_text

    def test_invalid_format_spec(self):
        """Test handling of invalid format specifications."""
        colored_text = "\x1b[31mTest\x1b[0m"
        ansi_str = AnsiString(colored_text)

        # Invalid width (non-numeric)
        result = f"{ansi_str:<abc}"
        assert result == colored_text  # Should return original text

        # Invalid alignment character
        result = f"{ansi_str:@10}"
        assert result == colored_text  # Should return original text

    def test_zero_width(self):
        """Test formatting with zero width."""
        colored_text = "\x1b[31mTest\x1b[0m"
        ansi_str = AnsiString(colored_text)
        result = f"{ansi_str:<0}"
        assert result == colored_text

    def test_empty_string_formatting(self):
        """Test formatting empty string."""
        ansi_str = AnsiString("")
        result = f"{ansi_str:<10}"
        assert result == "          "  # 10 spaces

    def test_only_ansi_codes(self):
        """Test string containing only ANSI codes."""
        only_ansi = "\x1b[31m\x1b[0m"  # No visible characters
        ansi_str = AnsiString(only_ansi)
        result = f"{ansi_str:<5}"
        assert result == only_ansi + "     "  # 5 spaces added


class TestAnsiStringComparison:
    """Test AnsiString comparison and hashing."""

    def test_equality_with_ansi_string(self):
        """Test equality comparison with another AnsiString."""
        text = "\x1b[31mRed\x1b[0m"
        ansi_str1 = AnsiString(text)
        ansi_str2 = AnsiString(text)
        assert ansi_str1 == ansi_str2

    def test_equality_with_string(self):
        """Test equality comparison with regular string."""
        text = "\x1b[31mRed\x1b[0m"
        ansi_str = AnsiString(text)
        assert ansi_str == text

    def test_inequality_different_text(self):
        """Test inequality with different text."""
        ansi_str1 = AnsiString("\x1b[31mRed\x1b[0m")
        ansi_str2 = AnsiString("\x1b[32mGreen\x1b[0m")
        assert ansi_str1 != ansi_str2

    def test_inequality_with_other_types(self):
        """Test inequality with non-string types."""
        ansi_str = AnsiString("test")
        assert ansi_str != 123
        assert ansi_str is not None
        assert ansi_str != []

    def test_hashable(self):
        """Test that AnsiString is hashable."""
        ansi_str = AnsiString("\x1b[31mRed\x1b[0m")
        hash_value = hash(ansi_str)
        assert isinstance(hash_value, int)

        # Same text should produce same hash
        ansi_str2 = AnsiString("\x1b[31mRed\x1b[0m")
        assert hash(ansi_str) == hash(ansi_str2)


class TestAnsiStringMethods:
    """Test additional AnsiString utility methods."""

    def test_startswith_string(self):
        """Test startswith with regular string."""
        colored_text = "\x1b[31mHello World\x1b[0m"
        ansi_str = AnsiString(colored_text)
        assert ansi_str.startswith("Hello")
        assert not ansi_str.startswith("World")

    def test_startswith_ansi_string(self):
        """Test startswith with another AnsiString."""
        colored_text = "\x1b[31mHello World\x1b[0m"
        ansi_str = AnsiString(colored_text)
        prefix_ansi = AnsiString("\x1b[32mHello\x1b[0m")
        assert ansi_str.startswith(prefix_ansi)

    def test_endswith_string(self):
        """Test endswith with regular string."""
        colored_text = "\x1b[31mHello World\x1b[0m"
        ansi_str = AnsiString(colored_text)
        assert ansi_str.endswith("World")
        assert not ansi_str.endswith("Hello")

    def test_endswith_ansi_string(self):
        """Test endswith with another AnsiString."""
        colored_text = "\x1b[31mHello World\x1b[0m"
        ansi_str = AnsiString(colored_text)
        suffix_ansi = AnsiString("\x1b[32mWorld\x1b[0m")
        assert ansi_str.endswith(suffix_ansi)


class TestAnsiStringIntegration:
    """Test AnsiString integration with real ANSI sequences."""

    def test_real_terminal_colors(self):
        """Test with realistic terminal color sequences."""
        # Red bold text
        red_bold = "\x1b[1;31mERROR\x1b[0m"
        ansi_str = AnsiString(red_bold)

        assert ansi_str.visible_text == "ERROR"
        assert len(ansi_str) == 5

        result = f"{ansi_str:>10}"
        expected = "     " + red_bold  # 5 spaces + colored text
        assert result == expected

    def test_multiple_color_changes(self):
        """Test text with multiple color changes."""
        multi_color = "\x1b[31mRed\x1b[32mGreen\x1b[34mBlue\x1b[0m"
        ansi_str = AnsiString(multi_color)

        assert ansi_str.visible_text == "RedGreenBlue"
        assert len(ansi_str) == 12

        result = f"{ansi_str:^20}"
        expected = "    " + multi_color + "    "  # Centered in 20 chars
        assert result == expected

    def test_background_and_foreground(self):
        """Test text with both background and foreground colors."""
        bg_fg = "\x1b[41;37mWhite on Red\x1b[0m"
        ansi_str = AnsiString(bg_fg)

        assert ansi_str.visible_text == "White on Red"
        assert len(ansi_str) == 12

        result = f"{ansi_str:*<20}"
        expected = bg_fg + "********"  # Padded with asterisks
        assert result == expected
