"""Validation module for MCA SDK.

This module provides validation for:
- Metric naming conventions (Story 2.6)
- Resource attributes (Story 2.5)
- Telemetry attributes (Story 3.6)
- Metric patterns and schemas
"""

from typing import Dict, List, Any

from .schema import (
    MetricNamingConvention,
    validate_metric_name,
    METRIC_PATTERNS,
    VALID_UNITS,
    VALID_PREFIXES,
)
from .naming_conventions import (
    is_valid_metric_name,
    sanitize_metric_name,
    METRIC_NAME_PATTERN,
    MIN_METRIC_NAME_LENGTH,
    MAX_METRIC_NAME_LENGTH,
)
from .validator import AttributeValidator
from .telemetry_attributes import TelemetryAttributeValidator
from .result import ValidationResult
from ..utils.exceptions import ValidationError
from .rules import (
    VALIDATION_RULES,
    get_validation_rules,
    ATTR_SERVICE_NAME,
    ATTR_MODEL_ID,
    ATTR_MODEL_VERSION,
    ATTR_MODEL_TYPE,
    ATTR_TEAM_NAME,
    ATTR_LLM_PROVIDER,
    ATTR_LLM_MODEL,
    ATTR_VENDOR_NAME,
    ATTR_SERVICE_VERSION,
    ATTR_DEPLOYMENT_ENV,
)

# Convenience constants for backward compatibility
# Map old-style model_type to required attributes
REQUIRED_ATTRIBUTES = {
    "internal": [ATTR_SERVICE_NAME, ATTR_MODEL_ID, ATTR_MODEL_VERSION, ATTR_TEAM_NAME],
    "generative": [ATTR_SERVICE_NAME, ATTR_LLM_PROVIDER, ATTR_LLM_MODEL, ATTR_TEAM_NAME],
    "vendor": [ATTR_SERVICE_NAME, ATTR_VENDOR_NAME, ATTR_TEAM_NAME],
}

# Recommended attributes (optional but useful)
RECOMMENDED_ATTRIBUTES = [ATTR_SERVICE_VERSION, ATTR_DEPLOYMENT_ENV]


def get_required_attributes(model_type: str) -> List[str]:
    """Get required attributes for a given model type (backward compatibility).

    Args:
        model_type: Either "internal", "generative", "vendor", or new taxonomy types

    Returns:
        List of required attribute names

    Raises:
        ValidationError: If model_type is invalid

    Note:
        This function provides backward compatibility. For new code, use
        get_validation_rules(model_category, model_type) instead.

    TODO(MCA-113): Refactor hardcoded if/else mapping to use validation rules
                   directly. This requires validation rules redesign to handle
                   backward-compatible taxonomy migration. Track in separate story.
    """
    # Handle new taxonomy types by mapping to old-style
    if model_type in ("regression", "time-series", "classification"):
        model_type = "internal"
    elif model_type in ("generative", "agentic"):
        model_type = "generative"

    if model_type not in REQUIRED_ATTRIBUTES:
        raise ValidationError(
            f"Invalid model_type: {model_type}. "
            f"Must be one of: {', '.join(REQUIRED_ATTRIBUTES.keys())}"
        )

    return REQUIRED_ATTRIBUTES[model_type].copy()


def get_recommended_attributes() -> List[str]:
    """Get recommended (optional) attributes.

    Returns:
        List of recommended attribute names
    """
    return RECOMMENDED_ATTRIBUTES.copy()


def validate_resource_attributes(
    attributes: Dict[str, Any],
    model_category: str = "internal",
    model_type: str = "regression",
    strict: bool = True,
) -> None:
    """Validate resource attributes for a given model taxonomy.

    Args:
        attributes: Dictionary of resource attributes
        model_category: High-level category ("internal" or "vendor")
        model_type: Specific type ("regression", "time-series", "classification",
                    "generative", "agentic")
        strict: If True, raise ValidationError on failure. If False, only log warnings.

    Raises:
        ValidationError: If required attributes are missing (strict mode only)

    Example:
        >>> validate_resource_attributes(
        ...     {"service.name": "test", "model.id": "mdl-001",
        ...      "model.version": "1.0", "team.name": "team"},
        ...     "internal", "regression"
        ... )  # OK
    """
    # Get validation rules for this taxonomy
    try:
        rules = get_validation_rules(model_category, model_type)
    except ValueError as e:
        raise ValidationError(f"Invalid taxonomy: {e}") from e

    required = rules["required"]
    missing = []
    invalid = []

    # Check required attributes
    for attr_name in required:
        value = attributes.get(attr_name)

        # SECURITY: None or empty string treated as missing (PHI leakage prevention)
        if value is None or (isinstance(value, str) and value.strip() == ""):
            missing.append(attr_name)
        # SECURITY: Validate attribute value length to prevent DoS
        elif isinstance(value, str) and len(value) > 1024:
            invalid.append(f"{attr_name} (exceeds maximum length of 1024 characters)")

    # If validation fails in strict mode, raise detailed error
    if (missing or invalid) and strict:
        error_parts = []

        if missing:
            error_parts.append(f"Missing required resource attributes: {', '.join(missing)}")

        if invalid:
            error_parts.append(f"Invalid attribute values: {', '.join(invalid)}")

        # Build helpful error message with configuration example
        from ..utils.routing import get_metric_prefix

        metric_prefix = get_metric_prefix(model_category, model_type)

        error_msg = "\n\n".join(error_parts)
        error_msg += "\n\nTo fix this, ensure your MCAClient configuration includes:\n\n"
        error_msg += "MCAClient(\n"

        for attr in required:
            # Map attribute name to config parameter
            param_name = attr.replace(".", "_")
            error_msg += f"    {param_name}='...',\n"

        error_msg += ")\n\n"
        error_msg += f"Metric prefix for this configuration: {metric_prefix}.*\n"
        error_msg += "\nTo disable strict validation, set strict_validation=False in MCAConfig."

        raise ValidationError(
            error_msg,
            missing_fields=missing,
            invalid_fields=None if not invalid else {item.split(" (")[0]: item for item in invalid},
            model_type=model_type,
            model_category=model_category,
        )


__all__ = [
    # Schema validation
    "MetricNamingConvention",
    "validate_metric_name",
    "MetricNamingConvention",
    "METRIC_PATTERNS",
    "VALID_UNITS",
    "VALID_PREFIXES",
    # General naming convention validation (Story 2.6)
    "is_valid_metric_name",
    "sanitize_metric_name",
    "METRIC_NAME_PATTERN",
    "MIN_METRIC_NAME_LENGTH",
    "MAX_METRIC_NAME_LENGTH",
    # Attribute validation (Story 2.5)
    "AttributeValidator",
    "validate_resource_attributes",
    "get_required_attributes",
    "get_recommended_attributes",
    "REQUIRED_ATTRIBUTES",
    # Telemetry attribute validation (Story 3.6)
    "TelemetryAttributeValidator",
    "ValidationResult",
    "ValidationError",
    "VALIDATION_RULES",
    "get_validation_rules",
    # Attribute name constants
    "ATTR_SERVICE_NAME",
    "ATTR_MODEL_ID",
    "ATTR_MODEL_VERSION",
    "ATTR_MODEL_TYPE",
    "ATTR_TEAM_NAME",
    "ATTR_LLM_PROVIDER",
    "ATTR_LLM_MODEL",
    "ATTR_VENDOR_NAME",
    "ATTR_SERVICE_VERSION",
    "ATTR_DEPLOYMENT_ENV",
]
