"""
Test type definitions and normalization utilities for the Galtea SDK.

This module provides the TestType enum and utilities for handling test type names.
The SDK accepts both the new user-facing names and legacy API names for backward compatibility.

New Names (User-Facing)     Legacy Names (API)
-----------------------     ------------------
ACCURACY                    QUALITY
SECURITY                    RED_TEAMING
BEHAVIOR                    SCENARIOS
"""

from enum import Enum
from typing import Union

from galtea.utils.case_insensitive_enum import CaseInsensitiveEnumMixin


class TestType(CaseInsensitiveEnumMixin, str, Enum):
    """
    Enum representing test types in Galtea.

    Each test type has a user-facing name and an API value:
    - ACCURACY: Tests that evaluate the quality and correctness of outputs (API: QUALITY)
    - SECURITY: Tests that evaluate security, safety, and bias aspects (API: RED_TEAMING)
    - BEHAVIOR: Tests that evaluate multi-turn dialogue interactions (API: SCENARIOS)

    Example:
        >>> from galtea.utils.test_type import TestType
        >>> test = galtea.tests.create(
        ...     name="my-test",
        ...     type=TestType.ACCURACY,  # or "ACCURACY" or "QUALITY"
        ...     product_id=product_id,
        ... )
    """

    ACCURACY = "QUALITY"
    SECURITY = "RED_TEAMING"
    BEHAVIOR = "SCENARIOS"

    # Legacy aliases (also valid as enum members for backward compatibility)
    QUALITY = "QUALITY"
    RED_TEAMING = "RED_TEAMING"
    SCENARIOS = "SCENARIOS"

    def __str__(self) -> str:
        """Return the API value when converted to string."""
        return self.value


# Mapping from user-facing names and variations to API values
_TEST_TYPE_ALIASES: dict[str, str] = {
    # New user-facing names (primary)
    "ACCURACY": "QUALITY",
    "SECURITY": "RED_TEAMING",
    "SECURITY_SAFETY": "RED_TEAMING",
    "SECURITY & SAFETY": "RED_TEAMING",
    "SECURITY_AND_SAFETY": "RED_TEAMING",
    "BEHAVIOR": "SCENARIOS",
    "BEHAVIOUR": "SCENARIOS",  # British spelling
    # Legacy API names (also supported)
    "QUALITY": "QUALITY",
    "RED_TEAMING": "RED_TEAMING",
    "REDTEAMING": "RED_TEAMING",
    "RED TEAMING": "RED_TEAMING",
    "SCENARIOS": "SCENARIOS",
    "USER_SCENARIOS": "SCENARIOS",
    "USER SCENARIOS": "SCENARIOS",
}


def normalize_test_type(test_type: Union[str, TestType]) -> str:
    """
    Normalize a test type input to the API value.

    Accepts both the new user-facing names (Accuracy, Security, Behavior)
    and the legacy API names (QUALITY, RED_TEAMING, SCENARIOS) for backward compatibility.

    Args:
        test_type: The test type as a string or TestType enum.
            Accepted values include:
            - New names: "ACCURACY", "SECURITY", "SECURITY & SAFETY", "BEHAVIOR"
            - Legacy names: "QUALITY", "RED_TEAMING", "SCENARIOS"
            - TestType enum values: TestType.ACCURACY, TestType.SECURITY, etc.

    Returns:
        The normalized API value (QUALITY, RED_TEAMING, or SCENARIOS).

    Raises:
        ValueError: If the test type is not recognized.

    Example:
        >>> normalize_test_type("ACCURACY")
        'QUALITY'
        >>> normalize_test_type("Security")
        'RED_TEAMING'
        >>> normalize_test_type(TestType.BEHAVIOR)
        'SCENARIOS'
        >>> normalize_test_type("QUALITY")  # Legacy name still works
        'QUALITY'
    """
    # Handle TestType enum
    if isinstance(test_type, TestType):
        return test_type.value

    # Handle string input
    if not isinstance(test_type, str):
        raise ValueError(f"test_type must be a string or TestType enum, got {type(test_type).__name__}")

    # Normalize the input: uppercase, replace hyphens/underscores with consistent format
    normalized: str = test_type.strip().upper()

    # Try to find a match in the aliases
    if normalized in _TEST_TYPE_ALIASES:
        return _TEST_TYPE_ALIASES[normalized]

    # Try with underscores instead of spaces
    normalized_underscore: str = normalized.replace(" ", "_").replace("-", "_")
    if normalized_underscore in _TEST_TYPE_ALIASES:
        return _TEST_TYPE_ALIASES[normalized_underscore]

    # If no match found, raise an error with helpful message
    valid_types: list[str] = [
        "ACCURACY (or QUALITY)",
        "SECURITY (or RED_TEAMING)",
        "BEHAVIOR (or SCENARIOS)",
    ]
    raise ValueError(f"Invalid test type: '{test_type}'. Valid test types are: {', '.join(valid_types)}.")
