"""Test type classification for self-healing safety.

Classifies tests by type (unit, integration, performance, security, etc.)
to prevent inappropriate automatic healing. Performance tests, security tests,
and property-based tests should never be auto-healed.
"""

from __future__ import annotations

import re
from enum import Enum, auto
from typing import Optional, Set


class TestType(Enum):
    """Classification of test types."""

    UNIT = auto()
    INTEGRATION = auto()
    END_TO_END = auto()
    PERFORMANCE = auto()
    SECURITY = auto()
    PROPERTY_BASED = auto()
    SNAPSHOT = auto()
    UNKNOWN = auto()


# Tests of these types should never be auto-healed
NEVER_HEAL_TYPES: Set[TestType] = {
    TestType.PERFORMANCE,
    TestType.SECURITY,
    TestType.PROPERTY_BASED,
    TestType.SNAPSHOT,
}

# Patterns for classifying tests by name
_NAME_PATTERNS = {
    TestType.PERFORMANCE: [
        re.compile(r"(?i)(perf|benchmark|load_test|stress_test|latency|throughput)"),
    ],
    TestType.SECURITY: [
        re.compile(r"(?i)(security|auth[nz]|xss|csrf|injection|pentest|vuln)"),
    ],
    TestType.PROPERTY_BASED: [
        re.compile(r"(?i)(property|fuzz|hypothesis|proptest|quickcheck)"),
    ],
    TestType.END_TO_END: [
        re.compile(r"(?i)(e2e|end[-._]?to[-._]?end|playwright|cypress|selenium)"),
    ],
    TestType.INTEGRATION: [
        re.compile(r"(?i)(integration|integ_)"),
    ],
    TestType.SNAPSHOT: [
        re.compile(r"(?i)(snapshot|snap_)"),
    ],
}

# Patterns for classifying tests by file path
_PATH_PATTERNS = {
    TestType.PERFORMANCE: [
        re.compile(r"(?i)(perf|benchmark|load)"),
    ],
    TestType.SECURITY: [
        re.compile(r"(?i)(security|[\b/]auth[nz]?[\b/])"),
    ],
    TestType.END_TO_END: [
        re.compile(r"(?i)(e2e|end[-._]?to[-._]?end|playwright|cypress|selenium)"),
    ],
    TestType.INTEGRATION: [
        re.compile(r"(?i)(integration|integ)"),
    ],
    TestType.SNAPSHOT: [
        re.compile(r"(?i)(snapshot|__snapshots__)"),
    ],
}

# Code-level markers that indicate test type
_CODE_MARKERS = {
    TestType.PROPERTY_BASED: [
        re.compile(r"@(given|settings|hypothesis)"),          # Python hypothesis
        re.compile(r"@(Property|QuickCheck)"),                # Java/Kotlin
        re.compile(r"#\[proptest\]"),                         # Rust proptest
        re.compile(r"fc\.(assert|property|check)"),           # JS fast-check
    ],
    TestType.PERFORMANCE: [
        re.compile(r"@pytest\.mark\.(benchmark|slow)"),
        re.compile(r"@(Benchmark|BenchmarkMode)"),            # Java JMH
        re.compile(r"bench\.iter\("),                         # Rust benchmark
        re.compile(r"(timeit|perf_counter|benchmark)"),
    ],
    TestType.SECURITY: [
        re.compile(r"@pytest\.mark\.security"),
        re.compile(r"(bandit|safety_check|vulnerability)"),
    ],
    TestType.UNIT: [
        re.compile(r"@pytest\.mark\.unit"),
    ],
    TestType.INTEGRATION: [
        re.compile(r"@pytest\.mark\.integration"),
    ],
    TestType.END_TO_END: [
        re.compile(r"@pytest\.mark\.e2e"),
    ],
    TestType.SNAPSHOT: [
        re.compile(r"(toMatchSnapshot|toMatchInlineSnapshot)"),    # Jest
        re.compile(r"(assert_snapshot|snapshot_test)"),             # Python
        re.compile(r"insta::assert_snapshot"),                     # Rust insta
    ],
}


class TestClassifier:
    """Classify tests by type to determine healing eligibility."""

    def classify(
        self,
        test_name: str,
        test_file: Optional[str] = None,
        test_code: Optional[str] = None,
    ) -> TestType:
        """Classify a test's type.

        Priority: code markers > name patterns > path patterns > UNKNOWN

        Args:
            test_name: Fully qualified test name
            test_file: Optional file path
            test_code: Optional test source code

        Returns:
            TestType classification
        """
        # Check code-level markers first (highest confidence)
        if test_code:
            for test_type, patterns in _CODE_MARKERS.items():
                for pattern in patterns:
                    if pattern.search(test_code):
                        return test_type

        # Check test name patterns
        for test_type, patterns in _NAME_PATTERNS.items():
            for pattern in patterns:
                if pattern.search(test_name):
                    return test_type

        # Check file path patterns
        if test_file:
            for test_type, patterns in _PATH_PATTERNS.items():
                for pattern in patterns:
                    if pattern.search(test_file):
                        return test_type

        return TestType.UNKNOWN

    def should_heal(self, test_type: TestType) -> bool:
        """Check if a test type is eligible for auto-healing.

        Args:
            test_type: The classified test type

        Returns:
            True if the test type can be auto-healed
        """
        return test_type not in NEVER_HEAL_TYPES
