import pandas as pd
import numpy as np
from scipy import stats

# 导入所需模块
import sys
import os

# 添加MFM目录到路径
current_dir = os.path.dirname(os.path.abspath(__file__))
# py_tools -> route -> FFEv3_2 -> FFE -> MFM -> 根目录
root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(current_dir)))))
if root_dir not in sys.path:
    sys.path.append(root_dir)

from myffe.tools.interactive import interactive
from myffe.tools.color_printer import ColorPrinter
from myffe.tools.len_match import len_match
from myffe.tools.visualize_route import visualize_route

def select_best_scaler(x):
    """选择最佳缩放器"""
    n = len(x)
    if n == 0:
        return "Z-score标准化"
    
    max_val = max(x)
    min_val = min(x)
    mean = np.mean(x)
    std = np.std(x)
    
    # 计算偏度和峰度
    skew = stats.skew(x)
    kurt = stats.kurtosis(x)
    
    # 计算四分位数
    q1 = np.percentile(x, 25)
    q3 = np.percentile(x, 75)
    iqr = q3 - q1
    total_range = max_val - min_val
    
    # 计算异常值比例
    outliers = []
    for val in x:
        if val < q1 - 1.5 * iqr or val > q3 + 1.5 * iqr:
            outliers.append(val)
    outlier_ratio = len(outliers) / n
    
    # 评分
    score_standard = abs(skew) + abs(kurt)  # 偏度和峰度越小越好
    score_minmax = 1.0 if total_range > 0 else 0.0  # 范围越大越好
    score_maxabs = 1.0 if max(abs(v) for v in x) > 0 else 0.0  # 绝对值越大越好
    score_robust = 1.0 - outlier_ratio  # 异常值越少，RobustScaler效果越好
    score_quantile = abs(skew)  # 偏度越大，QuantileTransformer效果越好
    
    # 计算均值归一化评分 - 基于数据的中心位置
    score_mean = 1.0 if abs(mean) > 0.1 else 0.0  # 均值不为零时效果更好
    
    # 计算单位长度归一化评分 - 基于数据的稀疏性
    non_zero_count = sum(1 for v in x if v != 0)
    score_unit = non_zero_count / n  # 非零值比例越高，效果越好
    
    # 计算自定义缩放评分 - 基于数据的整体分布
    score_custom = 1.0 - min(abs(skew), 1.0)  # 偏度越小，自定义缩放效果越好
    
    # 选择最佳评分
    scores = [score_standard, score_minmax, score_maxabs, score_robust, score_quantile, score_mean, score_unit, score_custom]
    best_index = scores.index(min(scores))  # 注意这里使用min，因为大多数评分越小越好
    
    scalers = ["Z-score标准化", "Min-Max标准化", "MaxAbs标准化", "RobustScaler标准化", "QuantileTransformer标准化", "均值归一化", "单位长度归一化", "自定义缩放"]
    return scalers[best_index]

def get_best_scaler(col):
    """获取最佳缩放器"""
    try:
        # 转换为数值类型
        data = [float(s) for s in col]
        return select_best_scaler(data)
    except ValueError:
        return "Z-score标准化"  # 默认值

def analyze_standardization(data, auto_test=False):
    """分析数据的标准化需求，为每列推荐适合的标准化方法
    
    Args:
        data: pandas DataFrame，输入数据
        auto_test: bool，是否自动测试模式，默认为 False
    
    Returns:
        dict: 包含标准化参数的字典，使用列名列表和方法列表的结构
    """
    standard_params = {
        'scaler_method_choice': [],
        'standard_col': []
    }

    scaler_methods = ["Z-score标准化", "Min-Max标准化", "MaxAbs标准化", "RobustScaler标准化", "QuantileTransformer标准化", "均值归一化", "单位长度归一化", "自定义缩放", "skip"]
    
    # 筛选出数值列
    numeric_columns = data.select_dtypes(include=['number']).columns.tolist()
    
    if not numeric_columns:
        ColorPrinter.print_info("数据中没有需要标准化的数值列")
        result = {
            'standard_preprocessing': standard_params
        }
        visualize_route(result)
        return result
    
    inter_standard = False
    if auto_test:
        print("\033[31m下面进行测试使用智能推荐\033[0m")
        inter_standard = True
    else:
        inter_standard_tem = interactive(['ok', 'no'] , title="智能推荐？", description="选择'ok'将自动为所有数值列推荐最佳标准化方法，选择'no'需要手动选择", min_select=1, max_select=1).run()
        if inter_standard_tem == 'ok':
            inter_standard = True
    
    if not inter_standard:
        while True:
            # 重置参数列表
            standard_params['standard_col'] = []
            standard_params['scaler_method_choice'] = []
            
            selected_cols = interactive(numeric_columns , title="请按上下箭头选择，回车确认标准化处理列,点击'm'键进行多选择", description="选择要进行标准化处理的列，可以多选", min_select=1, max_select=len(numeric_columns)).run()
            standard_params['standard_col'] = selected_cols
            time.sleep(2)
            ColorPrinter.print_success('你已选择标准化处理列：' + str(standard_params['standard_col']))
            
            # 为每列选择标准化方法
            for col in standard_params['standard_col']:
                selected_method = interactive(scaler_methods, title=f"请按上下箭头选择，回车确认{col}的标准化方法", description="Z-score标准化:基于均值和标准差, Min-Max标准化:缩放到0-1范围, MaxAbs标准化:基于最大值, RobustScaler标准化:对异常值不敏感, QuantileTransformer标准化:将数据映射到均匀分布, 均值归一化:减去均值, 单位长度归一化:缩放到单位范数, 自定义缩放:根据数据特性自定义, 跳过:不进行标准化处理", min_select=1, max_select=1).run()
                method = selected_method
                standard_params['scaler_method_choice'].append(method)
                time.sleep(2)
                ColorPrinter.print_success(f'你已选择{col}的标准化方法：{method}')
            
            # 检查列数量和方法数量是否匹配
            if not len_match(standard_params['standard_col'], standard_params['scaler_method_choice']):

                ColorPrinter.print_warning('请重新选择标准化方法')
                time.sleep(2)
                continue
            
            break
    else:
        # 智能推荐模式
        for col in numeric_columns:
            col_data = data[col].astype(str).tolist()
            best_method = get_best_scaler(col_data)
            standard_params['scaler_method_choice'].append(best_method)
            standard_params['standard_col'].append(col)
            ColorPrinter.print_info(f"为列 '{col}' 推荐标准化方法：{best_method}")
    
    # 过滤掉跳过的列
    filtered_columns = [] 
    filtered_methods = []
    for col, method in zip(standard_params['standard_col'], standard_params['scaler_method_choice']):
        if method != '跳过':
            filtered_columns.append(col)
            filtered_methods.append(method)
    
    standard_params['standard_col'] = filtered_columns
    standard_params['scaler_method_choice'] = filtered_methods
    
    result = {
        'standard_preprocessing': standard_params
    }
    visualize_route(result)
    return result

def standard_py(data, auto_test=False):
    """Python备用方案
    
    Args:
        data: pandas DataFrame，输入数据
        auto_test: bool，是否自动测试模式，默认为 False
    
    Returns:
        dict: 包含标准化参数的字典
    """
    return analyze_standardization(data, auto_test=auto_test)

if __name__ == "__main__":
    # 测试代码
    import pandas as pd
    import numpy as np
    
    # 创建测试数据
    np.random.seed(42)
    data = pd.DataFrame({
        'numeric_col1': np.random.normal(100, 10, 20),
        'numeric_col2': np.random.normal(50, 5, 20),
        'numeric_col3': np.random.uniform(0, 100, 20)
    })
    
    ColorPrinter.print_info("测试数据:")
    ColorPrinter.print_any(data.head(), color='white')
    ColorPrinter.print_any("\n数据统计:", color='blue')
    ColorPrinter.print_any(data.describe(), color='white')
    
    # 测试标准化处理
    ColorPrinter.print_info("\n测试标准化处理:")
    result = standard_py(data)
    ColorPrinter.print_success("处理结果:")
    ColorPrinter.print_any(result, color='white')




"""
这个输入data数据
这里这个函数最终会在self.route里添加一个
下面格式的字典
'standard_preprocessing': {
    'scaler_method_choice': [],
    'standard_col': []
}

scaler_method_choice的取值有
    "Z-score标准化"   # Z-score标准化
    "Min-Max标准化"   # Min-Max标准化
    "MaxAbs标准化"   # MaxAbs标准化
    "RobustScaler标准化"   # RobustScaler标准化
    "QuantileTransformer标准化"   # QuantileTransformer标准化，将数据映射到均匀分布
    "均值归一化"   # 均值归一化，减去均值
    "单位长度归一化"   # 单位长度归一化，缩放到单位范数
    "自定义缩放"   # 自定义缩放，根据数据特性自定义
    "跳过"   # 跳过标准化处理
"""

