"""
FFEv3.0 Feature Engineering Configuration

Based on FFEv2.0 with significant optimizations
Integrates preprocessing tools for comprehensive feature engineering

Main features:
1. Intelligent scheduling of preprocessing tools
2. Batch processing for large datasets
3. Detailed parameter configuration
"""

import sys
import os

# Import color printer
from myffe.tools.color_printer import ColorPrinter
# Import route visualization
from myffe.tools.visualize_route import visualize_route

# Preprocessing tools order - from basic to advanced
# This list defines the available preprocessing tools in FFE_config.py

# Preprocessing tools
clean_ways = [
    "nan_preprocessing",
    "autoencoder_preprocessing",
    "sample_preprocessing",
    "outlier_preprocessing",
    "str_preprocessing",
    "relative_preprocessing",
    "time_preprocessing",
    "specify_preprocessing",
    "standard_preprocessing",
    "normalized_preprocessing",
]




class FFE_config:
    """
    FFEv3.0 Feature Engineering Configuration
    
    Manages preprocessing tool configuration and initialization
    """
    
    def __init__(self, params_dict=None):
        """
        Initialize FFE configuration
        
        Args:
            params_dict (dict): Custom parameter dictionary {tool_name: {param_name: value}}
        """
        self.params_dict = params_dict if params_dict is not None else {}
        self.tools_dict = {}
        
        ColorPrinter.print_info("FFEv3.0 Feature Engineering Configuration")
        ColorPrinter.print_info("Available preprocessing tools:")
        for way in clean_ways:
            ColorPrinter.print_info(f"  - {way}")
        ColorPrinter.print_any("")
        
        # Visualize parameters if provided
        if self.params_dict:
            ColorPrinter.print_info("Configuration parameters:")
            visualize_route(self.params_dict)
    
    def __call__(self, tools):
        """
        Configure and initialize preprocessing tools
        
        Args:
            tools (list): List of preprocessing tool names or dictionaries
            
        Returns:
            dict: Initialized preprocessing tools dictionary
        """
        if isinstance(tools, list):
            return self.add_tools(tools)
        else:
            ColorPrinter.print_warning("Input must be a list of tools")
            return None
    
    def add_tools(self, tools):
        """
        Add and initialize preprocessing tools
        
        Args:
            tools (list): List of preprocessing tool names or dictionaries
            
        Returns:
            dict: Initialized preprocessing tools dictionary
        """
        self.tools_dict = {}
        tool_count = {}
        
        for tool in tools:
            # Extract tool name and parameters
            if isinstance(tool, dict) and len(tool) == 1:
                tool_name, tool_params = list(tool.items())[0]
            else:
                tool_name = tool
                # Use empty dict as default parameters
                tool_params = {}
            
            if tool_name not in clean_ways:
                ColorPrinter.print_warning(f"Warning: {tool_name} is not a valid preprocessing tool")
                continue
            
            # Check if tool should be skipped based on parameters
            skip_tool = False
            
            if tool_name == 'nan_preprocessing':
                if tool_params == 'skip' or (isinstance(tool_params, dict) and tool_params.get('nan_preprocessing') == 'skip') or ('nan_missing_process_choice' in tool_params):
                    if 'nan_missing_process_choice' in tool_params:
                        choices = tool_params['nan_missing_process_choice']
                        if choices is None:
                            skip_tool = True
                        elif isinstance(choices, list) and all('skip' in choice for choice in choices):
                            skip_tool = True
                    else:
                        skip_tool = True
            elif tool_name == 'sample_preprocessing':
                if 'sample_ways' in tool_params:
                    # 新格式：检查 sample_ways 中是否有非 skip 的方法
                    skip_tool = all('skip' in way.get('method', []) for way in tool_params['sample_ways'])
                else:
                    # 旧格式：保持原有逻辑
                    if 'choice1_normal' in tool_params and 'choice1_advance' in tool_params:
                        normal_choice = tool_params['choice1_normal']
                        advance_choice = tool_params['choice1_advance']
                        if (isinstance(normal_choice, list) and 'skip' in normal_choice) and \
                           (isinstance(advance_choice, list) and 'skip' in advance_choice):
                            skip_tool = True
            elif tool_name == 'outlier_preprocessing':
                if 'outlier_choice' in tool_params and tool_params['outlier_choice'] == 'skip':
                    skip_tool = True
            elif tool_name == 'str_preprocessing':
                if 'str_ways' in tool_params:
                    # 新格式：检查 str_ways 中是否有非 skip 的方法
                    skip_tool = all('skip' in way.get('method', []) for way in tool_params['str_ways'])
                elif ('clean_ways' in tool_params and not tool_params['clean_ways']) and \
                   ('str_choice' not in tool_params or tool_params['str_choice'] is None):
                    # 旧格式
                    skip_tool = True
            elif tool_name == 'relative_preprocessing':
                if 'choice3_normal' in tool_params and 'choice3_advance' in tool_params:
                    normal_choice = tool_params['choice3_normal']
                    advance_choice = tool_params['choice3_advance']
                    if (isinstance(normal_choice, list) and 'skip' in normal_choice) and \
                       (isinstance(advance_choice, list) and 'skip' in advance_choice):
                        skip_tool = True
            elif tool_name == 'time_preprocessing':
                if (isinstance(tool_params, dict) and tool_params.get('time_preprocessing') == 'skip') or ('time_col' in tool_params and tool_params['time_col'] is None):
                    skip_tool = True
            elif tool_name == 'standard_preprocessing':
                if tool_params == 'skip' or (isinstance(tool_params, dict) and tool_params.get('standard_preprocessing') == 'skip') or ('standard_ways' in tool_params and not tool_params['standard_ways']):
                    skip_tool = True
            elif tool_name == 'normalized_preprocessing':
                if tool_params == 'skip' or (isinstance(tool_params, dict) and tool_params.get('normalized_preprocessing') == 'skip') or ('normalized_ways' in tool_params and not tool_params['normalized_ways']):
                    skip_tool = True
            elif tool_name == 'specify_preprocessing':
                if tool_params == 'skip' or (isinstance(tool_params, dict) and tool_params.get('specify_preprocessing') == 'skip') or ('drop_col' not in tool_params and 'drop_row' not in tool_params):
                    skip_tool = True
            elif tool_name == 'autoencoder_preprocessing':
                if tool_params == 'skip' or (isinstance(tool_params, dict) and tool_params.get('autoencoder_preprocessing') == 'skip'):
                    skip_tool = True
            
            if skip_tool:
                ColorPrinter.print_warning(f"Skipping {tool_name} as it is configured to 'skip'")
                continue
            
            # Handle duplicate tool names
            if tool_name in tool_count:
                tool_count[tool_name] += 1
                unique_tool_name = f"{tool_name}_{tool_count[tool_name]}"
            else:
                tool_count[tool_name] = 1
                unique_tool_name = tool_name
            
            # Tool configuration mapping
            tool_config = {
                'nan_preprocessing': ('nan_preprocessing', 'NanPreprocessing', 'shortcut_nan'),
                'sample_preprocessing': ('sample_preprocessing', 'SamplePreprocessing', 'shortcut_sample'),
                'outlier_preprocessing': ('outlier_preprocessing', 'OutlierPreprocessing', 'shortcut_outlier'),
                'str_preprocessing': ('str_preprocessing', 'StrPreprocessing', 'shortcut_str'),
                'relative_preprocessing': ('relative_preprocessing', 'RelativePreprocessing', 'shortcut_relative'),
                'time_preprocessing': ('time_preprocessing', 'TimePreprocessing', 'shortcut_time'),
                'specify_preprocessing': ('specify_preprocessing', 'SpecifyPreprocessing', 'shortcut_specify'),
                'standard_preprocessing': ('standard_preprocessing', 'StandardScaler', 'shortcut_stand'),
                'normalized_preprocessing': ('normalized_preprocessing', 'Normalizer', 'shortcut_norm'),
                'autoencoder_preprocessing': ('autoencoder_preprocessing', 'AutoencoderPreprocessing', 'shortcut_autoencoder')
            }
            
            if tool_name in tool_config:
                module_name, class_name, param_name = tool_config[tool_name]
                # Import module
                module_path = f'myffe.preprocessing.{module_name}'
                module = __import__(module_path, fromlist=[class_name])
                # Get class from module
                cls = getattr(module, class_name)
                # Initialize tool with parameters
                if tool_name == 'nan_preprocessing':
                    # For NanPreprocessing, we need to pass label_col if available
                    label_col = self.params_dict.get('label_col') if self.params_dict else None
                    self.tools_dict[unique_tool_name] = cls(**{param_name: tool_params, 'label_col': label_col})
                else:
                    self.tools_dict[unique_tool_name] = cls(**{param_name: tool_params})
            else:
                ColorPrinter.print_error(f"Error: Unknown preprocessing tool {tool_name}")
        
        ColorPrinter.print_success(f"OK Initialized {len(self.tools_dict)} preprocessing tools")
        ColorPrinter.print_info(f"Tools: {list(self.tools_dict.keys())}")
        ColorPrinter.print_any("")
        
        # Visualize tool configurations
        if self.tools_dict:
            ColorPrinter.print_info("Tool configurations:")
            # Collect tool configurations
            tool_configs = {}
            for tool_name, tool_instance in self.tools_dict.items():
                # Extract parameters from tool instance
                if hasattr(tool_instance, 'shortcut_nan'):
                    tool_configs[tool_name] = tool_instance.shortcut_nan
                elif hasattr(tool_instance, 'shortcut_sample'):
                    tool_configs[tool_name] = tool_instance.shortcut_sample
                elif hasattr(tool_instance, 'shortcut_outlier'):
                    tool_configs[tool_name] = tool_instance.shortcut_outlier
                elif hasattr(tool_instance, 'shortcut_str'):
                    tool_configs[tool_name] = tool_instance.shortcut_str
                elif hasattr(tool_instance, 'shortcut_relative'):
                    tool_configs[tool_name] = tool_instance.shortcut_relative
                elif hasattr(tool_instance, 'shortcut_time'):
                    tool_configs[tool_name] = tool_instance.shortcut_time
                elif hasattr(tool_instance, 'shortcut_specify'):
                    tool_configs[tool_name] = tool_instance.shortcut_specify
                elif hasattr(tool_instance, 'shortcut_stand'):
                    tool_configs[tool_name] = tool_instance.shortcut_stand
                elif hasattr(tool_instance, 'shortcut_norm'):
                    tool_configs[tool_name] = tool_instance.shortcut_norm
                elif hasattr(tool_instance, 'shortcut_autoencoder'):
                    tool_configs[tool_name] = tool_instance.shortcut_autoencoder
            
            if tool_configs:
                visualize_route(tool_configs)
        
        return self.tools_dict
    

    
    def get_tools_dict(self):
        """
        Get tools dictionary
        
        Returns:
            dict: Preprocessing tools dictionary
        """
        return self.tools_dict
    
    def get_params_dict(self):
        """
        Get parameters dictionary
        
        Returns:
            dict: Configuration parameters
        """
        return self.params_dict
