"""Attribute validator module."""

import re

from ..config import MCAConfig
from ..utils.exceptions import ValidationError
from .result import ValidationResult
from .rules import (
    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,
)

# Pre-compile regex pattern for attribute value validation (performance optimization)
_ATTR_VALUE_PATTERN = re.compile(r"^[a-zA-Z0-9_.-]+$")


class AttributeValidator:
    """Validates resource attributes based on model type."""

    def __init__(self, config: MCAConfig, strict: bool = True):
        """
        Initialize validator.

        Args:
            config: MCAConfig with model_category, model_type, and attributes
            strict: If True, raise exception on validation failure
        """
        self.config = config
        self.strict = strict
        self.rules = get_validation_rules(config.model_category, config.model_type)

    def validate(self) -> ValidationResult:
        """
        Validate resource attributes.

        Returns:
            ValidationResult with is_valid, missing_fields, errors

        Raises:
            ValidationError: If strict=True and validation fails
        """
        missing_fields = []
        errors = []

        # Map config fields to attribute names
        # Note: getattr is used for optional fields that might not be in all config versions
        attribute_map = {
            ATTR_SERVICE_NAME: self.config.service_name,
            ATTR_MODEL_ID: self.config.model_id,
            ATTR_MODEL_VERSION: self.config.model_version,
            ATTR_TEAM_NAME: self.config.team_name,
            ATTR_LLM_PROVIDER: getattr(self.config, "llm_provider", None),
            ATTR_LLM_MODEL: getattr(self.config, "llm_model", None),
            ATTR_VENDOR_NAME: getattr(self.config, "vendor_name", None),
            ATTR_SERVICE_VERSION: getattr(self.config, "service_version", None),
            ATTR_DEPLOYMENT_ENV: getattr(self.config, "deployment_environment", None),
        }

        # For model.type: vendor models can provide custom descriptive types,
        # while internal/generative models use the taxonomy model_type
        if self.config.model_category == "vendor":
            # Vendor models: only set model.type if explicitly provided via vendor_model_type
            # Otherwise leave it None (optional per validation rules)
            attribute_map[ATTR_MODEL_TYPE] = getattr(self.config, "vendor_model_type", None)
        else:
            # Internal/generative models: use taxonomy model_type
            attribute_map[ATTR_MODEL_TYPE] = self.config.model_type

        # Check required fields
        for field in self.rules["required"]:
            value = attribute_map.get(field)

            if value is None or (isinstance(value, str) and value.strip() == ""):
                missing_fields.append(field)
                errors.append(f"Missing required attribute: {field}")
            elif not self._is_valid_value(field, value):
                # SECURITY: Never include raw value in error message (PHI leakage risk)
                errors.append(f"Invalid value for {field}")

        # Check optional fields (defense-in-depth validation)
        for field in self.rules["optional"]:
            value = attribute_map.get(field)
            # Only validate if provided (optional fields can be None/missing)
            if value is not None and isinstance(value, str) and value.strip():
                if not self._is_valid_value(field, value):
                    errors.append(f"Invalid value for {field}")

        # Create result
        is_valid = len(errors) == 0
        result = ValidationResult(is_valid=is_valid, missing_fields=missing_fields, errors=errors)

        # Raise exception in strict mode
        if not is_valid and self.strict:
            error_msg = (
                f"Validation failed for model_category={self.config.model_category}, "
                f"model_type={self.config.model_type}: {', '.join(errors)}"
            )
            if missing_fields:
                error_msg += f". Missing fields: {', '.join(missing_fields)}"
            raise ValidationError(error_msg, missing_fields=missing_fields)

        return result

    def _is_valid_value(self, field: str, value: str) -> bool:
        """Validate attribute value."""
        # Must be non-empty string
        if not isinstance(value, str) or not value.strip():
            return False

        # Length limit (security)
        if len(value) > 1024:
            return False

        # Special validation for critical fields (alphanumeric + dash + underscore + dot)
        # Prevents invalid characters from reaching OTLP exporters
        # Also validates optional fields for defense-in-depth
        if field in (
            ATTR_MODEL_ID,
            ATTR_SERVICE_NAME,
            ATTR_TEAM_NAME,
            ATTR_LLM_PROVIDER,
            ATTR_LLM_MODEL,
            ATTR_VENDOR_NAME,
            ATTR_MODEL_VERSION,
            ATTR_SERVICE_VERSION,
            ATTR_DEPLOYMENT_ENV,
        ):
            if not _ATTR_VALUE_PATTERN.match(value):
                return False

        return True
