"""Tests for regexvalidate module."""

from __future__ import annotations

import pytest

from pytola.dev.regexvalidate.gui import (
    PatternValidationError,
    RegexValidator,
    ValidationResult,
)


class TestRegexValidator:
    """Test cases for RegexValidator class."""

    def test_validator_initialization(self):
        """Test RegexValidator initialization with different patterns."""
        # Valid regex pattern
        validator = RegexValidator(r"\d+")
        assert validator.pattern == r"\d+"
        assert validator.flags == 0

        # Valid regex with flags
        import re

        validator = RegexValidator(r"[a-z]+", re.IGNORECASE)
        assert validator.flags == re.IGNORECASE

    def test_invalid_pattern_raises_error(self):
        """Test that invalid regex patterns raise PatternValidationError."""
        with pytest.raises(PatternValidationError) as exc_info:
            RegexValidator(r"[invalid(regex")

        assert "Invalid regex pattern" in str(exc_info.value)
        assert "unterminated character set" in str(exc_info.value)

    def test_validate_valid_text(self):
        """Test validation of text that matches the pattern."""
        validator = RegexValidator(r"\d{3}-\d{2}-\d{4}")

        result = validator.validate("123-45-6789")
        assert result.is_valid is True
        assert result.matches == ["123-45-6789"]
        assert result.error is None

    def test_validate_invalid_text(self):
        """Test validation of text that doesn't match the pattern."""
        validator = RegexValidator(r"\d{3}-\d{2}-\d{4}")

        result = validator.validate("invalid-text")
        assert result.is_valid is False
        assert result.matches == []
        assert result.error is not None
        assert "does not match pattern" in result.error

    def test_validate_multiple_matches(self):
        """Test validation finding multiple matches."""
        validator = RegexValidator(r"\b\d+\b")

        result = validator.validate("There are 123 and 456 numbers here")
        assert result.is_valid is True
        assert len(result.matches) == 2
        assert "123" in result.matches
        assert "456" in result.matches

    def test_validate_with_groups(self):
        """Test validation with capturing groups."""
        validator = RegexValidator(r"(\d{3})-(\d{2})-(\d{4})")

        result = validator.validate("123-45-6789")
        assert result.is_valid is True
        assert result.matches == ["123-45-6789"]

    def test_case_insensitive_matching(self):
        """Test case-insensitive pattern matching."""
        import re

        validator = RegexValidator(r"hello", re.IGNORECASE)

        # Should match both cases
        result1 = validator.validate("HELLO")
        result2 = validator.validate("hello")
        result3 = validator.validate("Hello")

        assert result1.is_valid is True
        assert result2.is_valid is True
        assert result3.is_valid is True

    def test_multiline_matching(self):
        """Test multiline pattern matching."""
        import re

        validator = RegexValidator(r"^start.*end$", re.MULTILINE)

        text = "start first line end\nother line\nstart second line end"
        result = validator.validate(text)
        assert result.is_valid is True
        assert len(result.matches) == 2

    def test_dotall_matching(self):
        """Test dotall pattern matching."""
        import re

        validator = RegexValidator(r"start.*end", re.DOTALL)

        text = "start\nmiddle\nend"
        result = validator.validate(text)
        assert result.is_valid is True
        assert len(result.matches) == 1

    def test_validate_empty_text(self):
        """Test validation of empty text."""
        validator = RegexValidator(r".*")  # Matches anything including empty

        result = validator.validate("")
        assert result.is_valid is True
        assert result.matches == [""]

    def test_validate_none_text(self):
        """Test validation of None text raises TypeError."""
        validator = RegexValidator(r".*")

        with pytest.raises(TypeError):
            validator.validate(None)

    def test_is_valid_method(self):
        """Test is_valid convenience method."""
        validator = RegexValidator(r"\d+")

        assert validator.is_valid("123") is True
        assert validator.is_valid("abc") is False

    def test_find_all_matches(self):
        """Test find_all_matches method."""
        validator = RegexValidator(r"\b\w{4,}\b")  # Words with 4+ characters

        text = "This is a test with several longer words"
        matches = validator.find_all_matches(text)
        assert len(matches) == 6
        assert "This" in matches
        assert "test" in matches
        assert "with" in matches
        assert "several" in matches
        assert "longer" in matches
        assert "words" in matches
        assert "a" not in matches  # Too short
        assert "is" not in matches  # Too short

    def test_find_all_matches_no_matches(self):
        """Test find_all_matches with no matches."""
        validator = RegexValidator(r"xyz123")

        matches = validator.find_all_matches("no matches here")
        assert matches == []

    def test_escape_pattern(self):
        """Test escape_pattern method."""
        # Test escaping special regex characters
        escaped = RegexValidator.escape_pattern("hello.world[regex]")
        assert escaped == r"hello\.world\[regex\]"

        # Test that escaped pattern can be used as literal
        validator = RegexValidator(escaped)
        result = validator.validate("hello.world[regex]")
        assert result.is_valid is True

    def test_get_pattern_info(self):
        """Test get_pattern_info method."""
        import re

        validator = RegexValidator(r"\d+", re.IGNORECASE | re.MULTILINE)

        info = validator.get_pattern_info()
        assert info["pattern"] == r"\d+"
        assert info["flags"] == re.IGNORECASE | re.MULTILINE
        assert "compiled_pattern" in info

    def test_result_string_representation(self):
        """Test ValidationResult string representation."""
        # Valid result
        valid_result = ValidationResult(is_valid=True, matches=["123"], error=None)
        assert "Valid" in str(valid_result)
        assert "1 match" in str(valid_result)

        # Invalid result
        invalid_result = ValidationResult(is_valid=False, matches=[], error="No match")
        assert "Invalid" in str(invalid_result)
        assert "No match" in str(invalid_result)

        # Multiple matches
        multi_result = ValidationResult(is_valid=True, matches=["a", "b", "c"], error=None)
        assert "3 matches" in str(multi_result)

    def test_validator_equality(self):
        """Test RegexValidator equality comparison."""
        import re

        validator1 = RegexValidator(r"\d+", re.IGNORECASE)
        validator2 = RegexValidator(r"\d+", re.IGNORECASE)
        validator3 = RegexValidator(r"\d+")
        validator4 = RegexValidator(r"[a-z]+")

        assert validator1 == validator2
        assert validator1 != validator3
        assert validator1 != validator4
        assert validator3 != validator4

    def test_validator_hash(self):
        """Test RegexValidator hash functionality."""
        import re

        validator1 = RegexValidator(r"\d+", re.IGNORECASE)
        validator2 = RegexValidator(r"\d+", re.IGNORECASE)

        # Equal validators should have same hash
        assert hash(validator1) == hash(validator2)

        # Can be used as dict keys
        validator_dict = {validator1: "test"}
        assert validator_dict[validator2] == "test"


class TestValidationResult:
    """Test cases for ValidationResult dataclass."""

    def test_result_creation(self):
        """Test ValidationResult creation."""
        result = ValidationResult(is_valid=True, matches=["test"], error=None)
        assert result.is_valid is True
        assert result.matches == ["test"]
        assert result.error is None

    def test_result_with_error(self):
        """Test ValidationResult with error."""
        result = ValidationResult(is_valid=False, matches=[], error="Invalid pattern")
        assert result.is_valid is False
        assert result.matches == []
        assert result.error == "Invalid pattern"

    def test_immutable_properties(self):
        """Test that ValidationResult properties are immutable."""
        result = ValidationResult(is_valid=True, matches=["test"], error=None)

        # These should be read-only
        with pytest.raises(AttributeError):
            result.is_valid = False
        with pytest.raises(AttributeError):
            result.matches = ["different"]
        with pytest.raises(AttributeError):
            result.error = "new error"
