"""Resource classification service for metadata stage."""

from typing import Tuple, List
import polars as pl
from .random_service import DeterministicRandomService


class ResourceClassificationService:
    """Service for classifying and splitting resources into processing groups."""

    def __init__(self, random_service: DeterministicRandomService):
        """Initialize with deterministic random service for consistent splits."""
        self.random_service = random_service

    def classify_k8s_vs_non_k8s(self, df: pl.DataFrame) -> Tuple[pl.DataFrame, pl.DataFrame]:
        """
        Split resources into K8s and Non-K8s groups based on k8s_cluster column.

        Args:
            df: DataFrame with resources

        Returns:
            Tuple of (k8s_resources, non_k8s_resources)
        """
        if df.height == 0:
            return df.clone(), df.clone()

        # Check if k8s_cluster column exists
        if "k8s_cluster" not in df.columns:
            # No k8s_cluster column means all resources are non-k8s
            return df.filter(pl.lit(False)), df.clone()  # Empty k8s, all non-k8s

        # K8s resources have non-null, non-empty k8s_cluster values
        k8s_resources = df.filter(
            pl.col("k8s_cluster").is_not_null() &
            (pl.col("k8s_cluster") != "") &
            (pl.col("k8s_cluster") != "__UNALLOCATED__")
        )

        # Non-K8s resources have null, empty, or __UNALLOCATED__ k8s_cluster values
        non_k8s_resources = df.filter(
            pl.col("k8s_cluster").is_null() |
            (pl.col("k8s_cluster") == "") |
            (pl.col("k8s_cluster") == "__UNALLOCATED__")
        )

        return k8s_resources, non_k8s_resources

    def split_k8s_namespaces(self, k8s_df: pl.DataFrame) -> Tuple[pl.DataFrame, pl.DataFrame]:
        """
        Split K8s resources into labels group and namespace injection group.

        Only processes custom namespaces (non-default, non-UNALLOCATED).
        Default/system namespaces are excluded from processing.

        Args:
            k8s_df: DataFrame with K8s resources (must have k8s_namespace column)

        Returns:
            Tuple of (labels_group, namespace_injection_group) - both containing only custom namespaces
        """
        if k8s_df.height == 0:
            return k8s_df.clone(), k8s_df.clone()

        # Check if k8s_namespace column exists
        if "k8s_namespace" not in k8s_df.columns:
            # No namespace column means no K8s processing
            return k8s_df.filter(pl.lit(False)), k8s_df.filter(pl.lit(False))

        # Define default/system namespaces to exclude
        default_namespaces = ["default", "kube-system", "kube-public", "kube-node-lease", "__UNALLOCATED__"]

        # Filter to only custom namespaces (non-default, non-UNALLOCATED, non-empty, non-null)
        custom_namespace_resources = k8s_df.filter(
            pl.col("k8s_namespace").is_not_null() &
            (pl.col("k8s_namespace") != "") &
            (~pl.col("k8s_namespace").is_in(default_namespaces))
        )

        if custom_namespace_resources.height == 0:
            return custom_namespace_resources.clone(), custom_namespace_resources.clone()

        # Get unique custom namespaces
        unique_namespaces = (
            custom_namespace_resources
            .select("k8s_namespace")
            .unique()
            .to_series()
            .to_list()
        )

        if len(unique_namespaces) == 0:
            return custom_namespace_resources.filter(pl.lit(False)), custom_namespace_resources.filter(pl.lit(False))

        # Split namespaces 50/50 deterministically
        labels_namespaces = []
        namespace_injection_namespaces = []

        for namespace in unique_namespaces:
            # Create deterministic fingerprint for namespace splitting
            fingerprint = f"{self.random_service.dataset_name}:k8s_namespace_split:{namespace}"
            hash_val = hash(fingerprint) % 2

            if hash_val == 0:
                labels_namespaces.append(namespace)
            else:
                namespace_injection_namespaces.append(namespace)

        # Filter resources by namespace assignment
        labels_group = custom_namespace_resources.filter(
            pl.col("k8s_namespace").is_in(labels_namespaces)
        ) if labels_namespaces else custom_namespace_resources.filter(pl.lit(False))

        namespace_injection_group = custom_namespace_resources.filter(
            pl.col("k8s_namespace").is_in(namespace_injection_namespaces)
        ) if namespace_injection_namespaces else custom_namespace_resources.filter(pl.lit(False))

        return labels_group, namespace_injection_group

    def split_non_k8s_resources(self, non_k8s_df: pl.DataFrame) -> Tuple[pl.DataFrame, pl.DataFrame]:
        """
        Split non-K8s resources into tags group and resource ID injection group.

        Args:
            non_k8s_df: DataFrame with non-K8s resources

        Returns:
            Tuple of (tags_group, resource_id_injection_group) split 50/50
        """
        if non_k8s_df.height == 0:
            return non_k8s_df.clone(), non_k8s_df.clone()

        # Use deterministic random service to split 50/50
        return self.random_service.split_resources_50_50(non_k8s_df, "non_k8s_split")

    def get_default_namespaces(self) -> List[str]:
        """Get list of default/system namespaces that are excluded from processing."""
        return ["default", "kube-system", "kube-public", "kube-node-lease", "__UNALLOCATED__"]

    def validate_k8s_resource_requirements(self, k8s_df: pl.DataFrame) -> List[str]:
        """
        Validate that K8s resources have required columns for processing.

        Args:
            k8s_df: DataFrame with K8s resources

        Returns:
            List of validation errors (empty if valid)
        """
        errors = []

        if k8s_df.height == 0:
            return errors

        required_k8s_columns = ["k8s_cluster", "k8s_namespace"]
        missing_columns = [col for col in required_k8s_columns if col not in k8s_df.columns]

        if missing_columns:
            errors.append(f"K8s resources missing required columns: {missing_columns}")

        return errors

    def get_processing_summary(self, df: pl.DataFrame) -> dict:
        """
        Get summary of resource classification for debugging/logging.

        Args:
            df: Original DataFrame with all resources

        Returns:
            Dictionary with classification statistics
        """
        k8s_resources, non_k8s_resources = self.classify_k8s_vs_non_k8s(df)

        summary = {
            "total_resources": df.height,
            "k8s_resources": k8s_resources.height,
            "non_k8s_resources": non_k8s_resources.height,
            "k8s_breakdown": {},
            "non_k8s_breakdown": {}
        }

        # K8s breakdown
        if k8s_resources.height > 0:
            labels_group, namespace_injection_group = self.split_k8s_namespaces(k8s_resources)

            # Get unique custom namespaces for reporting
            if "k8s_namespace" in k8s_resources.columns:
                default_namespaces = self.get_default_namespaces()
                custom_namespaces = (
                    k8s_resources
                    .filter(
                        pl.col("k8s_namespace").is_not_null() &
                        (pl.col("k8s_namespace") != "") &
                        (~pl.col("k8s_namespace").is_in(default_namespaces))
                    )
                    .select("k8s_namespace")
                    .unique()
                    .to_series()
                    .to_list()
                )

                summary["k8s_breakdown"] = {
                    "labels_group": labels_group.height,
                    "namespace_injection_group": namespace_injection_group.height,
                    "custom_namespaces_count": len(custom_namespaces),
                    "custom_namespaces": custom_namespaces
                }

        # Non-K8s breakdown
        if non_k8s_resources.height > 0:
            tags_group, resource_id_group = self.split_non_k8s_resources(non_k8s_resources)
            summary["non_k8s_breakdown"] = {
                "tags_group": tags_group.height,
                "resource_id_injection_group": resource_id_group.height
            }

        return summary