"""Processor factory with selective activation following V1 pattern."""

from typing import List, Dict, Type
import polars as pl
from .processors.base import DiscountProcessor
from .processors.aws_processors import AWSSpotProcessor, AWSReservedInstanceProcessor, AWSSavingsPlanProcessor
from .processors.azure_processors import AzureSpotProcessor, AzureReservationProcessor, AzureSavingsPlanProcessor
from .processors.gcp_processors import GCPCUDProcessor, GCPSpotProcessor
from ...log_context.core import get_logger


class ProcessorFactory:
    """Factory for creating cached discount processor instances with selective activation.
    
    Follows V1 selective activation pattern where only specific processors are currently enabled.
    This allows easy activation/deactivation of discount types without code changes.
    """
    
    _processor_cache: Dict[Type[DiscountProcessor], DiscountProcessor] = {}
    
    # Current selective activation - only Spot processors + GCP CUD are enabled
    # This matches the V1 pattern where most discount types are disabled
    ACTIVE_PROCESSORS = {
        "AWS": [
            # AWSReservedInstanceProcessor,     # Disabled
            # AWSSavingsPlanProcessor,          # Disabled  
            AWSSpotProcessor,                   # Active
        ],
        "Azure": [
            # AzureReservationProcessor,        # Disabled
            # AzureSavingsPlanProcessor,        # Disabled
            AzureSpotProcessor,                 # Active
        ],
        "GCP": [
            GCPCUDProcessor,                    # Active
            GCPSpotProcessor,                   # Active
        ]
    }
    
    @classmethod
    def get_active_processors(cls, provider: str) -> List[DiscountProcessor]:
        """Get currently active processors for a provider.
        
        Args:
            provider: Cloud provider name ("AWS", "Azure", "GCP")
            
        Returns:
            List of active processor instances for the provider
        """
        logger = get_logger(__name__)
        
        processor_classes = cls.ACTIVE_PROCESSORS.get(provider, [])
        
        if not processor_classes:
            logger.debug(f"No active processors configured for provider: {provider}")
            return []
        
        processors = []
        for processor_class in processor_classes:
            processor = cls._get_cached_processor(processor_class)
            processors.append(processor)
        
        logger.debug(
            f"Retrieved active processors for {provider}",
            active_processors=[p.__class__.__name__ for p in processors]
        )
        
        return processors
    
    @classmethod
    def get_all_active_processors(cls) -> Dict[str, List[DiscountProcessor]]:
        """Get all active processors for all providers.
        
        Returns:
            Dictionary mapping provider to list of active processors
        """
        all_processors = {}
        for provider in cls.ACTIVE_PROCESSORS.keys():
            processors = cls.get_active_processors(provider)
            if processors:  # Only include providers with active processors
                all_processors[provider] = processors
        return all_processors
    
    @classmethod
    def _get_cached_processor(cls, processor_class: Type[DiscountProcessor]) -> DiscountProcessor:
        """Get cached processor instance, creating if necessary.
        
        Args:
            processor_class: Processor class to instantiate
            
        Returns:
            Cached processor instance
        """
        if processor_class not in cls._processor_cache:
            cls._processor_cache[processor_class] = processor_class()
        return cls._processor_cache[processor_class]
    
    @classmethod
    def clear_cache(cls) -> None:
        """Clear processor cache. Useful for testing or memory management."""
        cls._processor_cache.clear()
    
    @classmethod
    def get_processor_info(cls) -> Dict[str, Dict[str, any]]:
        """Get information about all available processors and their activation status.
        
        Returns:
            Dictionary with processor information for debugging/reporting
        """
        all_processors = {
            "AWS": [AWSSpotProcessor, AWSReservedInstanceProcessor, AWSSavingsPlanProcessor],
            "Azure": [AzureSpotProcessor, AzureReservationProcessor, AzureSavingsPlanProcessor],
            "GCP": [GCPCUDProcessor, GCPSpotProcessor]
        }
        
        info = {}
        for provider, processors in all_processors.items():
            info[provider] = {}
            active_classes = cls.ACTIVE_PROCESSORS.get(provider, [])
            
            for processor_class in processors:
                is_active = processor_class in active_classes
                processor_instance = processor_class()
                
                info[provider][processor_class.__name__] = {
                    "active": is_active,
                    "discount_percentage": processor_instance.discount_percentage,
                    "discount_range": processor_instance.discount_range,
                    "relevant_services": processor_instance.get_relevant_services()
                }
        
        return info


def apply_discount_processors(data, provider: str, already_discounted: set = None):
    """Convenience function to apply all active discount processors for a provider.
    
    Args:
        data: Input DataFrame
        provider: Cloud provider name
        already_discounted: Set of already discounted resource IDs
        
    Returns:
        Tuple of (enhanced_data, updated_already_discounted_set)
    """
    if already_discounted is None:
        already_discounted = set()
    
    logger = get_logger(__name__)
    processors = ProcessorFactory.get_active_processors(provider)
    
    if not processors:
        logger.debug(f"No active processors for {provider}, adding default discount columns")
        # Add default discount columns when no processors are active
        enhanced_data = data.with_columns([
            pl.lit(0.0).alias("discount_amount"),
            pl.lit("").alias("discount_type")
        ])
        return enhanced_data, already_discounted
    
    enhanced_data = data
    updated_already_discounted = already_discounted.copy()
    
    for processor in processors:
        enhanced_data, newly_discounted = processor.apply_discount(
            enhanced_data, updated_already_discounted
        )
        updated_already_discounted.update(newly_discounted)
    
    logger.info(
        f"Applied {len(processors)} discount processors for {provider}",
        processors=[p.__class__.__name__ for p in processors],
        newly_discounted=len(updated_already_discounted) - len(already_discounted)
    )
    
    return enhanced_data, updated_already_discounted