"""K8s namespace injection service for metadata stage."""

import polars as pl
from src.log_context import get_logger
from ..config import KeyConfig
from .random_service import DeterministicRandomService
from .value_sanitizer import K8sValueSanitizer


class K8sNamespaceInjectionService:
    """Service for injecting values into K8s namespace names (tags_only=false scenario)."""

    def __init__(self, random_service: DeterministicRandomService, value_sanitizer: K8sValueSanitizer):
        """
        Initialize with dependencies.

        Args:
            random_service: Service for deterministic value allocation
            value_sanitizer: Service for sanitizing values before injection
        """
        self.random_service = random_service
        self.value_sanitizer = value_sanitizer
        self.logger = get_logger(__name__)

    def inject_into_namespaces(self, df: pl.DataFrame, key_config: KeyConfig) -> pl.DataFrame:
        """
        Inject values into custom K8s namespace names with validation.

        Transforms: custom-app → custom-app-pulse-analytics

        Sanitizes values and validates final names are DNS subdomain compliant.

        Args:
            df: DataFrame with K8s resources (must have k8s_namespace column)
            key_config: Key configuration with values to inject

        Returns:
            DataFrame with modified k8s_namespace column

        Raises:
            ValueError: If injection would create invalid namespace names
        """
        if df.height == 0:
            return df

        if "k8s_namespace" not in df.columns:
            raise ValueError("DataFrame must have 'k8s_namespace' column for namespace injection")

        # Sanitize values before injection
        sanitized_values = self.value_sanitizer.sanitize_values(key_config.values)

        self.logger.info(
            "Sanitized metadata values for k8s injection",
            key_name=key_config.key_name,
            original_count=len(key_config.values),
            sanitized_count=len(sanitized_values)
        )

        # Get unique namespaces for validation
        unique_namespaces = df.select("k8s_namespace").unique()
        unique_namespace_list = unique_namespaces["k8s_namespace"].to_list()

        # Pre-validate injection safety (length check)
        is_safe, error = self.value_sanitizer.validate_injection_safety(
            unique_namespace_list,
            sanitized_values
        )
        if not is_safe:
            raise ValueError(f"Cannot inject metadata into k8s namespaces: {error}")

        # Create sanitized key config
        sanitized_key_config = KeyConfig(
            key_name=key_config.key_name,
            values=sanitized_values,
            tags_only=key_config.tags_only
        )

        # For namespace injection, we allocate values per namespace, not per resource
        # This ensures all resources in the same namespace get the same suffix
        namespace_value_mapping = self._create_namespace_value_mapping(
            unique_namespaces, sanitized_key_config
        )

        # Join back to get the allocated value for each resource's namespace
        df_with_mapping = df.join(
            namespace_value_mapping,
            on="k8s_namespace",
            how="left"
        )

        # Inject values into namespace names
        value_column = f"_namespace_value_{key_config.key_name}"

        result = df_with_mapping.with_columns([
            self._inject_namespace_value_expression(value_column).alias("k8s_namespace")
        ]).drop(value_column)

        return result

    def _create_namespace_value_mapping(
        self,
        unique_namespaces: pl.DataFrame,
        key_config: KeyConfig
    ) -> pl.DataFrame:
        """
        Create mapping from namespace to allocated value.

        Args:
            unique_namespaces: DataFrame with unique k8s_namespace values
            key_config: Key configuration with values to allocate

        Returns:
            DataFrame with k8s_namespace and allocated value columns
        """
        if unique_namespaces.height == 0:
            return unique_namespaces.with_columns([
                pl.lit(None, dtype=pl.Utf8).alias(f"_namespace_value_{key_config.key_name}")
            ])

        # Create a temporary DataFrame with required columns for random service
        # We'll use namespace as the "resource_id" for consistent allocation
        temp_df = unique_namespaces.with_columns([
            pl.lit("k8s").alias("cloud_provider"),  # Dummy provider
            pl.lit("namespace").alias("service"),   # Dummy service
            pl.col("k8s_namespace").alias("resource_id")  # Use namespace as resource_id
        ])

        # Use deterministic random service to allocate values per namespace
        result = self.random_service.allocate_values_to_resources(
            df=temp_df,
            values=key_config.values,
            context=f"k8s_namespace_injection:{key_config.key_name}",
            column_name=f"_namespace_value_{key_config.key_name}"
        )

        # Return only the namespace and value columns
        return result.select([
            pl.col("k8s_namespace"),
            pl.col(f"_namespace_value_{key_config.key_name}")
        ])

    def _inject_namespace_value_expression(self, value_column: str) -> pl.Expr:
        """
        Create Polars expression for injecting value into namespace name.

        Args:
            value_column: Column containing the value to inject

        Returns:
            Polars expression for modified k8s_namespace
        """
        return pl.concat_str([
            pl.col("k8s_namespace"),
            pl.lit("-"),
            pl.col(value_column)
        ])