"""
FFEv3.0 Feature Engineering Console

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 preprocessing execution
4. Real-time quality assessment
5. Comprehensive processing reports
6. Data visualization support
7. Logging system integration
8. Easy-to-use API
"""

import sys
import os
import pandas as pd
import time
import json
from datetime import datetime

# Add MFM project root to Python path
sys.path.append(os.path.abspath('.'))

from myffe.tools.color_printer import ColorPrinter
from myffe.core.master_judge import evaluate_dataset, print_evaluation_result

# Preprocessing tools order - from basic to advanced
clean_ways = [
    "nan_preprocessing",      # 1. Missing value handling
    "outlier_preprocessing",  # 2. Outlier detection
    "str_preprocessing",      # 3. Text feature processing
    "time_preprocessing",     # 4. Time feature processing
    "relative_preprocessing", # 5. Relative feature processing
    "specify_preprocessing",  # 6. Custom feature processing
    "sample_preprocessing",   # 7. Data sampling
    "standard_preprocessing", # 8. Standardization
    "normalized_preprocessing", # 9. Normalization
]


class FFE_console:
    """
    FFEv3.0 Feature Engineering Console
    """
    
    def __init__(self, data_label, ways='auto', batch_size=None, enable_logging=True, enable_visualization=True, enable_quality_assessment=True, use_modin=False):
        """
        Initialize FFE console

        Args:
            data_label (str): Label column name
            ways (str): Processing method
                - 'auto': Automatic tool ordering
                - 'intelligent': Intelligent tool ordering based on data analysis
                - 'pass': Use tools in provided order
            batch_size (int): Batch size for large data processing, None for no batching
            enable_logging (bool): Whether to enable logging, default True
            enable_visualization (bool): Whether to enable visualization, default True
            enable_quality_assessment (bool): Whether to enable quality assessment, default True
            use_modin (bool): Whether to use Modin for data processing, default False
        """
        self.data_label = data_label
        self.ways = ways
        self.batch_size = batch_size
        self.enable_logging = enable_logging
        self.enable_visualization = enable_visualization
        self.enable_quality_assessment = enable_quality_assessment
        self.use_modin = use_modin
        self.data = None
        self.text_features = None
        self.str_confirm = False
        self.performance_stats = {}
        self.quality_metrics = {}
        self.processing_history = []
        
        ColorPrinter.print_info("FFEv3.0 Feature Engineering Console")
        ColorPrinter.print_info(f"Label: {data_label}")
        ColorPrinter.print_info(f"Processing way: {ways}")
        if batch_size:
            ColorPrinter.print_info(f"Batch size: {batch_size}")
        ColorPrinter.print_info(f"Logging: {'Enabled' if enable_logging else 'Disabled'}")
        ColorPrinter.print_info(f"Visualization: {'Enabled' if enable_visualization else 'Disabled'}")
        ColorPrinter.print_info(f"Quality assessment: {'Enabled' if enable_quality_assessment else 'Disabled'}")
        ColorPrinter.print_any("")
    
    def __call__(self, clean_tools, data, save_path='./clean_data/data00.csv', describe_data=True):
        """
        Execute feature engineering with preprocessing tools

        Args:
            clean_tools (dict): Preprocessing tools dictionary
            data (DataFrame): Input data
            save_path (str): Path to save processed data
            describe_data (bool): Whether to describe data before and after processing, default True

        Returns:
            DataFrame: Processed data
        """
        start_time = time.time()
        
        # 备份原始标签列
        original_label_data = None
        if self.data_label in data.columns:
            original_label_data = data[[self.data_label]].copy()
            ColorPrinter.print_info(f"已备份原始标签列: {self.data_label}")
        
        # Check if Modin should be used
        if self.use_modin:
            try:
                import modin.pandas as pd
                # Convert pandas DataFrame to Modin DataFrame if needed
                if not hasattr(data, '_query_compiler'):
                    data = pd.DataFrame(data)
                ColorPrinter.print_info("Using Modin for data processing")
            except ImportError:
                ColorPrinter.print_warning("Modin not installed, falling back to pandas")
                import pandas as pd
        else:
            import pandas as pd
        
        self.clean_ways_dict = clean_tools
        self.data = data.copy()
        self.save_path = save_path
        
        # Configure logging
        try:
            from myffe.tools.Loggerv1_1 import set_logging_enabled
            set_logging_enabled(self.enable_logging)
            # Logging configuration based on enable_logging parameter
        except ImportError:
            ColorPrinter.print_warning("Warning: Failed to configure logging system")
        
        # Processed data description
        if describe_data:
            # Separate label column if it exists for description
            if self.data_label in self.data.columns:
                label_data = self.data[[self.data_label]].copy()
                feature_data = self.data.drop(columns=[self.data_label])
            else:
                label_data = None
                feature_data = self.data.copy()
            self._describe_data(feature_data, label_data, "Original Data Description")
        
        # Initial data quality assessment
        if self.enable_quality_assessment:
            self._assess_data_quality(self.data, "initial")
        
        # Tool ordering
        self.sorting(self.clean_ways_dict)
        
        # Execute preprocessing
        self.clean_console()
        
        # Merge text features if available
        if self.str_confirm and self.text_features is not None:
            self.data = pd.concat([self.data, self.text_features], axis=1)
            ColorPrinter.print_success("OK Text features merged successfully")
        
        # 验证标签列是否被修改
        if original_label_data is not None and self.data_label in self.data.columns:
            current_label_data = self.data[[self.data_label]]
            
            # 计算差异
            try:
                # 确保两个DataFrame具有相同的索引和列
                if original_label_data.index.equals(current_label_data.index) and original_label_data.columns.equals(current_label_data.columns):
                    diff_count = (original_label_data != current_label_data).sum().iloc[0]
                else:
                    # 如果索引或列不同，尝试对齐后再比较
                    aligned_original = original_label_data.reindex(current_label_data.index)
                    diff_count = (aligned_original != current_label_data).sum().iloc[0]
                total_count = len(current_label_data)
                diff_ratio = diff_count / total_count if total_count > 0 else 0
            except Exception as e:
                ColorPrinter.print_error(f"比较标签列时出错: {e}")
                # 默认为没有差异
                diff_count = 0
                total_count = len(current_label_data)
                diff_ratio = 0
            
            if diff_ratio > 0.2:
                ColorPrinter.print_error(f"错误: 标签列 '{self.data_label}' 被修改的比例超过20% ({diff_ratio:.2f})")
                ColorPrinter.print_error(f"差异数量: {diff_count}/{total_count}")
                raise ValueError(f"标签列 '{self.data_label}' 被修改的比例超过20%，请检查预处理工具")
            elif diff_ratio > 0:
                ColorPrinter.print_warning(f"警告: 标签列 '{self.data_label}' 被修改 ({diff_ratio:.2f})")
                ColorPrinter.print_warning(f"差异数量: {diff_count}/{total_count}")
                # 恢复原始标签列
                ColorPrinter.print_info("使用原始标签列替换修改后的标签列")
                self.data[self.data_label] = original_label_data[self.data_label]
            else:
                ColorPrinter.print_info(f"标签列 '{self.data_label}' 未被修改，保持原始状态")
        
        # Final data quality assessment
        if self.enable_quality_assessment:
            self._assess_data_quality(self.data, "final")
        
        # Save processed data
        self.save_data()
        
        # Processed data description
        if describe_data:
            # Separate label column if it exists for description
            if self.data_label in self.data.columns:
                label_data = self.data[[self.data_label]].copy()
                feature_data = self.data.drop(columns=[self.data_label])
            else:
                label_data = None
                feature_data = self.data.copy()
            self._describe_data(feature_data, label_data, "Processed Data Description")
        
        # Generate processing report
        self._generate_processing_report(start_time)
        
        return self.data
    
    def sorting(self, clean_tools):
        """
        Sort preprocessing tools based on selected method
        
        Args:
            clean_tools (dict): Preprocessing tools dictionary
        """
        if self.ways == 'auto':
            sorted_dict = {}
            for tool_name in clean_ways:
                if tool_name in clean_tools:
                    sorted_dict[tool_name] = clean_tools[tool_name]
            self.clean_ways_dict = sorted_dict
        elif self.ways == 'intelligent':
            # Intelligent tool ordering based on data analysis
            sorted_dict = self._intelligent_sorting(clean_tools)
            self.clean_ways_dict = sorted_dict
        elif self.ways == 'pass':
            self.clean_ways_dict = clean_tools
        else:
            ColorPrinter.print_error(f"Invalid processing way: {self.ways}, using pass mode")
            self.clean_ways_dict = clean_tools
    
    def clean_console(self):
        """
        Execute preprocessing tools on data
        """
        try:
            if self.batch_size is not None and len(self.data) > self.batch_size:
                self.data = self._process_in_batches()
            else:
                self.data = self._process_single_batch(self.data)
        except Exception as e:
            ColorPrinter.print_error(f"Processing error: {e}")
            raise
    
    def _assess_quality(self, data, label_data):
        """
        Assess data quality by combining with label if available
        
        Args:
            data (DataFrame): Feature data
            label_data (DataFrame): Label data
            
        Returns:
            dict: Quality metrics
        """
        # Combine with label for quality assessment if available
        if label_data is not None:
            assessment_data = pd.concat([data, label_data], axis=1)
        else:
            assessment_data = data
        return self._calculate_quality_metrics(assessment_data)
    
    def _describe_data(self, data, label_data, title):
        """
        Describe data by combining with label if available
        
        Args:
            data (DataFrame): Feature data
            label_data (DataFrame): Label data
            title (str): Description title
        """
        ColorPrinter.print_any("\n" + "=" * 80)
        ColorPrinter.print_info(title)
        ColorPrinter.print_any("=" * 80)
        try:
            from myffe.tools.data_description import describe_data
            # Combine with label for description if available
            if label_data is not None:
                describe_data(pd.concat([data, label_data], axis=1))
            else:
                describe_data(data)
        except ImportError:
            ColorPrinter.print_warning("Warning: Failed to load data description module")
        ColorPrinter.print_any("=" * 80 + "\n")
    
    def _process_single_batch(self, batch_data):
        """
        Process a single batch of data
        
        Args:
            batch_data (DataFrame): Batch of data to process
            
        Returns:
            DataFrame: Processed data
        """
        # Separate label column if it exists
        if self.data_label in batch_data.columns:
            label_data = batch_data[[self.data_label]].copy()
            feature_data = batch_data.drop(columns=[self.data_label])
        else:
            label_data = None
            feature_data = batch_data.copy()
        
        processed_data = feature_data.copy()
        
        # ==================== 标签列处理逻辑 ====================
        # 1. 需要标签列的工具列表
        # 这些工具在处理过程中需要访问标签列信息
        tools_needing_label = ['outlier_preprocessing', 'str_preprocessing', 'relative_preprocessing', 'sample_preprocessing']
        # - outlier_preprocessing: 可能需要根据标签列进行异常值检测
        # - str_preprocessing: 可能需要根据标签列进行文本特征处理
        # - relative_preprocessing: 需要标签列计算相对特征
        # - sample_preprocessing: 需要标签列进行分层采样
        
        for tool_name in self.clean_ways_dict.keys():
            ColorPrinter.print_info(f"Processing: {tool_name}")
            start_tool_time = time.time()
            
            # Pre-quality assessment
            if self.enable_quality_assessment:
                pre_quality = self._assess_quality(processed_data, label_data)
            
            # ==================== 标签列处理流程 ====================
            # 2. 标签列的处理流程
            # 对于需要标签列的工具，将标签列与特征数据组合后传递
            if tool_name in tools_needing_label and label_data is not None:
                try:
                    # a. 创建标签列的副本以保护原始标签
                    label_data_copy = label_data.copy()
                    # b. 将特征数据与标签列组合
                    data_with_label = pd.concat([processed_data, label_data_copy], axis=1)
                    # c. 执行预处理工具，传入包含标签列的数据
                    processed_data_with_label = self._execute_preprocessing(tool_name, data_with_label)
                    # d. 从处理后的数据中提取特征和标签
                    if self.data_label in processed_data_with_label.columns:
                        # 分离特征数据和标签列
                        processed_data = processed_data_with_label.drop(columns=[self.data_label])
                        label_data = processed_data_with_label[[self.data_label]].copy()
                        ColorPrinter.print_info(f"Label column '{self.data_label}' preserved after {tool_name}")
                    else:
                        # 如果处理后的数据中没有标签列，保留原始标签数据
                        processed_data = processed_data_with_label
                        ColorPrinter.print_warning(f"Label column '{self.data_label}' not found in processed data from {tool_name}, keeping original labels")
                except Exception as e:
                    ColorPrinter.print_error(f"Error processing {tool_name} with label: {str(e)}")
                    # 发生错误时保留原始数据
                    ColorPrinter.print_info(f"Keeping original data for {tool_name}")
            else:
                try:
                    processed_data = self._execute_preprocessing(tool_name, processed_data)
                except Exception as e:
                    ColorPrinter.print_error(f"Error processing {tool_name}: {str(e)}")
                    # Keep original data if error occurs
                    ColorPrinter.print_info(f"Keeping original data for {tool_name}")
            
            # Post-quality assessment
            if self.enable_quality_assessment:
                post_quality = self._assess_quality(processed_data, label_data)
                quality_change = {k: post_quality.get(k, 0) - pre_quality.get(k, 0) for k in set(pre_quality.keys())}
                self.processing_history.append({
                    'tool': tool_name,
                    'execution_time': time.time() - start_tool_time,
                    'quality_change': quality_change
                })
            else:
                self.processing_history.append({
                    'tool': tool_name,
                    'execution_time': time.time() - start_tool_time
                })
            
            # Processed data description
            self._describe_data(processed_data, label_data, f"After {tool_name} Processing")
            
            ColorPrinter.print_success(f"OK {tool_name} completed (Time: {time.time() - start_tool_time:.2f} s)")
        
        # ==================== 最终返回结果的处理 ====================
        # 4. 最终返回结果的处理
        # 所有预处理工具执行完成后，重新附加标签列
        if label_data is not None:
            # 将处理后的特征数据与标签列重新组合
            # 这样返回的结果包含完整的特征和标签
            processed_data = pd.concat([processed_data, label_data], axis=1)
        
        # 返回处理后的完整数据（包含标签列，如果存在）
        return processed_data
    
    def _process_in_batches(self):
        """
        Process data in batches

        Returns:
            DataFrame: Processed data
        """
        ColorPrinter.print_warning(f"Processing in batches: {self.batch_size}")
        ColorPrinter.print_info(f"Total rows: {len(self.data)}")
        ColorPrinter.print_info(f"Number of batches: {(len(self.data) + self.batch_size - 1) // self.batch_size}")
        ColorPrinter.print_any("")

        # Create batch data list
        batches = []
        batch_count = 0

        for i in range(0, len(self.data), self.batch_size):
            batch_count += 1
            batch_data = self.data.iloc[i:i + self.batch_size].copy()
            batches.append((batch_count, batch_data, i+1, min(i+self.batch_size, len(self.data))))

        # Use multiprocessing for parallel processing
        try:
            import multiprocessing
            from multiprocessing import Pool

            # Determine number of processes to use
            num_processes = min(multiprocessing.cpu_count(), len(batches))
            ColorPrinter.print_info(f"Using {num_processes} processes for parallel processing")

            # Process batches in parallel
            with Pool(processes=num_processes) as pool:
                results = pool.starmap(self._process_batch_wrapper, batches)

            # Collect results
            batch_data_list = []
            for batch_count, processed_batch in results:
                batch_data_list.append(processed_batch)
                ColorPrinter.print_success(f"OK Batch {batch_count} completed")

        except ImportError:
            # Fallback to sequential processing if multiprocessing is not available
            ColorPrinter.print_warning("Multiprocessing not available, falling back to sequential processing")
            batch_data_list = []
            for batch_count, batch_data, start_row, end_row in batches:
                ColorPrinter.print_warning(f"Batch {batch_count}: Rows {start_row}-{end_row}")
                processed_batch = self._process_single_batch(batch_data)
                batch_data_list.append(processed_batch)
                ColorPrinter.print_success(f"OK Batch {batch_count} completed")
                ColorPrinter.print_any("")

        processed_data = pd.concat(batch_data_list, ignore_index=True)
        ColorPrinter.print_success(f"All {len(batches)} batches processed successfully")
        return processed_data

    def _process_batch_wrapper(self, batch_count, batch_data, start_row, end_row):
        """
        Wrapper function for batch processing in multiprocessing

        Args:
            batch_count (int): Batch number
            batch_data (DataFrame): Batch data
            start_row (int): Start row index
            end_row (int): End row index

        Returns:
            tuple: (batch_count, processed_batch)
        """
        import sys
        import os

        # Add the project root to Python path for each process
        sys.path.append(os.path.abspath('.'))

        # Process the batch
        processed_batch = self._process_single_batch(batch_data)
        return (batch_count, processed_batch)
    
    def _execute_preprocessing(self, tool_name, data):
        """
        Execute preprocessing tool
        
        Args:
            tool_name (str): Preprocessing tool name
            data (DataFrame): Input data (可能包含标签列，取决于工具是否需要)
            
        Returns:
            DataFrame: Processed data
        """
        # ==================== 标签列的使用方式 ====================
        # 3. 标签列在预处理工具中的使用方式
        # 不同工具对标签列的使用方式不同，以下是具体说明：
        processor = self.clean_ways_dict.get(tool_name)
        
        if processor is None:
            ColorPrinter.print_error(f"Error: Preprocessing tool {tool_name} not found")
            return data
        
        # Handle NaN values for standardization and normalization
        if tool_name in ['standard_preprocessing', 'normalized_preprocessing']:
            numeric_cols = data.select_dtypes(include=['number']).columns
            if numeric_cols.size > 0:
                # Check for NaN values
                has_nan = data[numeric_cols].isnull().any().any()
                if has_nan:
                    ColorPrinter.print_warning(f"Warning: {tool_name} requires no NaN values, filling with mean")
                    # Fill NaN values
                    for col in numeric_cols:
                        if data[col].isnull().any().any():
                            data[col] = data[col].fillna(data[col].mean())
                            ColorPrinter.print_info(f"  Filled NaN values in {col}")
        
        # Execute preprocessing based on tool type
        if tool_name == 'nan_preprocessing':
            # Get clean_type from processor, default to normal
            params = processor.shortcut_nan
            # 传入整个数据（包含标签列）和标签列名
            # 用途：处理缺失值时可能需要考虑标签列的完整性
            return processor(data)  # Pass label column name
        
        elif tool_name == 'sample_preprocessing':
            # Get clean_type from processor, default to normal
            params = processor.shortcut_sample
            # 传入整个数据（包含标签列）、处理类型和标签列名
            # 用途：进行分层采样，保持标签分布一致性
            return processor(data, 'normal', self.data_label)
        
        elif tool_name == 'outlier_preprocessing':
            # Get parameters from processor, default to normal
            # 传入整个数据（包含标签列）和标签列名
            # 用途：可能根据标签列进行异常值检测，例如检测特定类别中的异常值
            return processor(data, self.data_label)  # Pass label column name
        
        elif tool_name == 'str_preprocessing':
            # 传入整个数据（包含标签列）和标签列名
            # 用途：可能根据标签列进行文本特征的处理和转换
            result = processor(data, self.data_label)  # Pass label column name
            # Handle text features
            if isinstance(result, tuple):
                processed_data, text_features = result
                if not self.str_confirm:
                    self.text_features = text_features
                self.str_confirm = True
            else:
                processed_data = result
            return processed_data
        
        elif tool_name == 'relative_preprocessing':
            # Get clean_type from processor, default to normal
            params = processor.shortcut_relative
            # 传入整个数据（包含标签列）、处理类型和标签列名
            # 用途：计算与标签相关的相对特征
            relative_type = params.get('relative_type', 'normal')
            return processor(data, relative_type, self.data_label)  # Pass label column name
        
        elif tool_name == 'time_preprocessing':
            # 对于新格式，不需要传递time_type参数
            # 每个时间列有独立的处理类型配置
            return processor(data)
        
        elif tool_name == 'specify_preprocessing':
            # Get clean_type from processor, default to normal
            params = processor.shortcut_specify
            return processor(data)  # No label column needed
        
        elif tool_name == 'standard_preprocessing':
            # Get parameters from processor and execute
            try:
                # Execute processor directly on data
                processed_data = processor(data)
                return processed_data
            except Exception as e:
                ColorPrinter.print_error(f"Error in standard_preprocessing: {str(e)}")
                return data
        
        elif tool_name == 'normalized_preprocessing':
            # Get parameters from processor and execute
            try:
                # Execute processor directly on data
                processed_data = processor(data)
                return processed_data
            except Exception as e:
                ColorPrinter.print_error(f"Error in normalized_preprocessing: {str(e)}")
                return data
        
        else:
            ColorPrinter.print_error(f"Error: Unknown preprocessing tool {tool_name}")
            return data
    
    def save_data(self):
        """
        Save processed data to file
        """
        if self.save_path:
            save_dir = os.path.dirname(self.save_path)
            if save_dir and not os.path.exists(save_dir):
                os.makedirs(save_dir)
            
            self.data.to_csv(self.save_path, index=False)
            ColorPrinter.print_success(f"\nData saved to: {self.save_path}")
            ColorPrinter.print_info(f"Shape: {self.data.shape}")
            ColorPrinter.print_info(f"Columns: {len(self.data.columns)}")
    
    def _intelligent_sorting(self, clean_tools):
        """
        Intelligently sort preprocessing tools based on data analysis
        
        Args:
            clean_tools (dict): Preprocessing tools dictionary
            
        Returns:
            dict: Sorted preprocessing tools
        """
        # Analyze data
        data_analysis = {
            'has_nan': self.data.isnull().any().any(),
            'has_outliers': False,  # Placeholder for outlier detection
            'has_text': any(self.data.dtypes == 'object'),
            'has_time': False,  # Placeholder for time feature detection
            'needs_sampling': len(self.data) > 10000,  # Simple heuristic for sampling
        }
        
        # Intelligent tool order
        intelligent_order = []
        
        # 1. Handle missing values first
        if data_analysis['has_nan'] and 'nan_preprocessing' in clean_tools:
            intelligent_order.append('nan_preprocessing')
        
        # 2. Handle outliers
        if data_analysis['has_outliers'] and 'outlier_preprocessing' in clean_tools:
            intelligent_order.append('outlier_preprocessing')
        
        # 3. Process text features
        if data_analysis['has_text'] and 'str_preprocessing' in clean_tools:
            intelligent_order.append('str_preprocessing')
        
        # 4. Process time features
        if data_analysis['has_time'] and 'time_preprocessing' in clean_tools:
            intelligent_order.append('time_preprocessing')
        
        # 5. Relative feature processing
        if 'relative_preprocessing' in clean_tools:
            intelligent_order.append('relative_preprocessing')
        
        # 6. Custom feature processing
        if 'specify_preprocessing' in clean_tools:
            intelligent_order.append('specify_preprocessing')
        
        # 7. Data sampling (if needed)
        if data_analysis['needs_sampling'] and 'sample_preprocessing' in clean_tools:
            intelligent_order.append('sample_preprocessing')
        
        # 8. Normalization and standardization
        if 'standard_preprocessing' in clean_tools:
            intelligent_order.append('standard_preprocessing')
        if 'normalized_preprocessing' in clean_tools:
            intelligent_order.append('normalized_preprocessing')
        
        # Create sorted dictionary
        sorted_dict = {}
        for tool_name in intelligent_order:
            if tool_name in clean_tools:
                sorted_dict[tool_name] = clean_tools[tool_name]
        
        # Add remaining tools
        for tool_name in clean_tools:
            if tool_name not in sorted_dict:
                sorted_dict[tool_name] = clean_tools[tool_name]
        
        ColorPrinter.print_warning(f"Intelligent order: {list(sorted_dict.keys())}")
        return sorted_dict
    
    def _assess_data_quality(self, data, stage):
        """
        Assess data quality
        
        Args:
            data (DataFrame): Data to assess
            stage (str): Stage of processing (initial, final)
        """
        # 使用新的评价系统
        evaluation_result = evaluate_dataset(data, label_column=self.data_label)
        
        # 保持向后兼容的质量指标
        metrics = self._calculate_quality_metrics(data)
        self.quality_metrics[stage] = metrics
        
        if self.enable_visualization:
            ColorPrinter.print_info(f"\n{stage} Data Quality Metrics:")
            # 打印新的评价结果
            print_evaluation_result(evaluation_result)
            # 保持原有的指标输出以保持兼容性
            ColorPrinter.print_info("\nTraditional Quality Metrics:")
            for key, value in metrics.items():
                ColorPrinter.print_info(f"  - {key}: {value:.4f}")
    
    def _calculate_quality_metrics(self, data):
        """
        Calculate data quality metrics
        
        Args:
            data (DataFrame): Data to analyze
            
        Returns:
            dict: Quality metrics
        """
        metrics = {}
        
        # Missing value ratio
        total_cells = data.size
        missing_cells = data.isnull().sum().sum()
        metrics['missing_value_ratio'] = missing_cells / total_cells if total_cells > 0 else 0
        
        # Data type diversity
        unique_dtypes = len(data.dtypes.unique())
        metrics['dtype_diversity'] = unique_dtypes / len(data.columns) if len(data.columns) > 0 else 0
        
        # Mean variance of numeric features
        numeric_cols = data.select_dtypes(include=['number']).columns
        if len(numeric_cols) > 0:
            variances = data[numeric_cols].var()
            metrics['mean_variance'] = variances.mean() if len(variances) > 0 else 0
        else:
            metrics['mean_variance'] = 0
        
        # Feature count
        metrics['feature_count'] = len(data.columns)
        
        return metrics
    
    def _generate_processing_report(self, start_time):
        """
        Generate processing report

        Args:
            start_time (float): Start time of processing
        """
        import os
        total_time = time.time() - start_time

        ColorPrinter.print_info("\n" + "=" * 80)
        ColorPrinter.print_info("Processing Summary")
        ColorPrinter.print_info("=" * 80)
        ColorPrinter.print_info(f"Total time: {total_time:.2f} s")
        ColorPrinter.print_info(f"Tools executed: {len(self.processing_history)}")

        if self.processing_history:
            ColorPrinter.print_info("\nTool execution times:")
            for item in self.processing_history:
                tool_name = item['tool']
                exec_time = item['execution_time']
                ColorPrinter.print_info(f"  - {tool_name}: {exec_time:.2f} s")
                if 'quality_change' in item:
                    ColorPrinter.print_info("    Quality changes:")
                    for key, value in item['quality_change'].items():
                        if value != 0:
                            ColorPrinter.print_info(f"      {key}: {value:+.4f}")

        if self.quality_metrics:
            ColorPrinter.print_info("\nQuality metrics comparison:")
            initial_metrics = self.quality_metrics.get('initial', {})
            final_metrics = self.quality_metrics.get('final', {})
            for key in set(initial_metrics.keys()) | set(final_metrics.keys()):
                initial_val = initial_metrics.get(key, 0)
                final_val = final_metrics.get(key, 0)
                change = final_val - initial_val
                ColorPrinter.print_info(f"  - {key}: {initial_val:.4f} → {final_val:.4f} ({change:+.4f})")

        # Save report to file if save_path is provided
        if self.save_path:
            report_path = os.path.join(os.path.dirname(self.save_path), f"processing_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json")
            report_data = {
                'total_time': total_time,
                'tools_executed': len(self.processing_history),
                'processing_history': self.processing_history,
                'quality_metrics': self.quality_metrics,
                'data_shape': list(self.data.shape),
                'feature_count': len(self.data.columns)
            }

            # Create directory if it doesn't exist
            os.makedirs(os.path.dirname(report_path), exist_ok=True)

            with open(report_path, 'w', encoding='utf-8') as f:
                json.dump(report_data, f, ensure_ascii=False, indent=2)

            ColorPrinter.print_info(f"Report saved to: {report_path}")
        ColorPrinter.print_info("=" * 80 + "\n")


def main():
    """
    Main function for command-line execution
    """
    import argparse
    import pandas as pd
    
    parser = argparse.ArgumentParser(description='FFE v3.2 Feature Engineering Console')
    parser.add_argument('--data', type=str, required=True, help='Path to input CSV file')
    parser.add_argument('--label', type=str, required=True, help='Label column name')
    parser.add_argument('--output', type=str, default='./clean_data/data00.csv', help='Output file path')
    parser.add_argument('--ways', type=str, default='auto', choices=['auto', 'intelligent', 'pass'], help='Processing way')
    parser.add_argument('--batch-size', type=int, default=None, help='Batch size for large data processing')
    
    args = parser.parse_args()
    
    # Load data
    ColorPrinter.print_info(f"Loading data: {args.data}")
    data = pd.read_csv(args.data)
    ColorPrinter.print_success(f"OK Data loaded successfully: {data.shape}")
    
    # Import preprocessing tools
    try:
        from myffe.preprocessing import NanPreprocessing, OutlierPreprocessing, StrPreprocessing, TimePreprocessing, RelativePreprocessing, SpecifyPreprocessing, SamplePreprocessing, StandardScaler, Normalizer
    except ImportError as e:
        ColorPrinter.print_error(f"Import error: {e}")
        return
    
    # Create preprocessing tools dictionary
    clean_tools = {
        'nan_preprocessing': NanPreprocessing(shortcut_nan={'nan_missing_process_choice': ['skip'], 'nan_processing_col': []}),
        'outlier_preprocessing': OutlierPreprocessing(shortcut_outlier={'outlier_choice': 'skip'}),
        'str_preprocessing': StrPreprocessing(shortcut_str={'str_choice': 'skip', 'str_cols': []}),
        'time_preprocessing': TimePreprocessing(shortcut_time={'time_col': None}),
        'relative_preprocessing': RelativePreprocessing(shortcut_relative={'choice3_normal': ['skip'], 'choice3_advance': ['skip']}),
        'specify_preprocessing': SpecifyPreprocessing(shortcut_specify={'drop_col': [], 'drop_row': []}),
        'sample_preprocessing': SamplePreprocessing(shortcut_sample={'choice1_normal': ['skip'], 'choice1_advance': ['skip']}),
        'standard_preprocessing': StandardScaler(),
        'normalized_preprocessing': Normalizer()
    }
    
    # Create FFE console
    console = FFE_console(args.label, ways=args.ways, batch_size=args.batch_size)
    
    # Execute processing
    console(clean_tools, data, save_path=args.output)
    
    ColorPrinter.print_success("FFE processing completed")


if __name__ == "__main__":
    main()
