import sys
import os

# 添加项目根目录到Python路径
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')))

from myffe.tools.Loggerv1_1 import log_class
from myffe.tools.color_printer import ColorPrinter
from myffe.tools.evaluation_decorator import with_evaluation
from myffe.tools.data_inspector import inspect_data
import pandas as pd
import numpy as np

"""
Time preprocessing module

Supported time formats:
- ISO format: 2023-01-01, 2023-01-01T12:00:00
- US format: 01/01/2023, 01/01/2023 12:00:00
- European format: 01.01.2023, 01.01.2023 12:00:00
- Chinese format: 2023年01月01日, 2023-01-01 12:00:00
- Timestamp: 1672531200 (seconds), 1672531200000 (milliseconds)
- Other pandas-recognizable time formats

This module automatically handles NaN values in time columns, using forward and backward filling to handle missing values.
"""

@log_class(type='use')
class TimePreprocessing:
    #region 初始化方法
    def __init__(self, shortcut_time=None):
        """初始化时间预处理处理器
        
        Args:
            shortcut_time: 时间处理参数，包含time_ways配置
        """
        self.shortcut_time = shortcut_time 
    #endregion

    #region 主处理方法
    @with_evaluation
    def __call__(self, data=None, time_type=None):
        """执行时间预处理
        
        Args:
            data: 输入数据
            time_type: 时间处理类型（未使用）
            
        Returns:
            处理后的数据
        """
#region 对于skip情况
        if self.shortcut_time == 'skip':
            ColorPrinter.print_info('跳过时间处理，因为参数配置为 "skip"')
            return data
#endregion
#region 获取参数
        time_ways = self.shortcut_time.get('time_ways')
#endregion
#region 正式处理时间列
        if time_ways:
            for time_config in time_ways:
#region 获取时间列参数
                col = time_config.get('time_col')
                col_time_type = time_config.get('time_type', 'basic')
#endregion
                if col:
                    if col_time_type == 'basic':
                        data = self.preprocessor_time(data, col)
                    elif col_time_type == 'advance':
                        data = self.preprocessor_time(data, col, time_type='advance')
                    else:
                        ColorPrinter.print_error(f'时间列 {col} 的处理类型不正确')
#endregion     
        return data
    #endregion
    #region 基础时间处理
    def preprocessor_time(self, data, time_col, time_type='normal'):
        """处理时间列并提取基础时间特征
        
        Args:
            data: 输入数据
            time_col: 时间列名
            time_type: 时间处理类型 ('normal' 或 'advance')
            
        Returns:
            处理后的数据
        """                                                                                            
        # 增强时间格式自动识别
        try:
            # 尝试多种时间格式解析
            data[time_col] = pd.to_datetime(data[time_col])
        except Exception as e:
            ColorPrinter.print_warning(f"时间格式解析失败: {e}")
            ColorPrinter.print_info("尝试使用更宽松的解析方式...")
            # 使用更宽松的解析方式
            data[time_col] = pd.to_datetime(data[time_col], errors='coerce')
        
        # 检查时间列是否成功转换为datetime类型
        if not pd.api.types.is_datetime64_any_dtype(data[time_col]):
            ColorPrinter.print_warning(f"警告: 无法将列 {time_col} 转换为时间格式，跳过时间处理")
            return data
        
        # 检查并处理时间列中的NaN值
        if data[time_col].isnull().any():
            null_count = data[time_col].isnull().sum()
            ColorPrinter.print_warning(f"时间列 {time_col} 中检测到 {null_count} 个NaN值，将自动填充为最近的有效时间")
            data[time_col] = data[time_col].ffill().bfill()
        
        # 基础时间特征
        try:
            # 为特征列添加时间列前缀，避免多列时间处理时的列名冲突
            prefix = f"{time_col}_"
            
            data[f'{prefix}year'] = data[time_col].dt.year
            data[f'{prefix}month'] = data[time_col].dt.month
            data[f'{prefix}day'] = data[time_col].dt.day
            
            # 时间戳特征
            data[f'{prefix}timestamp'] = data[time_col].astype(np.int64) // 10**9  # 秒级时间戳
            
            # 增加小时、分钟、秒特征（如果时间列包含时分秒信息）
            try:
                data[f'{prefix}hour'] = data[time_col].dt.hour
                data[f'{prefix}minute'] = data[time_col].dt.minute
                data[f'{prefix}second'] = data[time_col].dt.second
            except Exception:
                # 如果时间列不包含时分秒信息，跳过这些特征
                pass
            
            if time_type == 'advance':
                data = self.high_preprocessor_time(data, time_col)
            
            # 删除原始时间列
            ColorPrinter.print_info(f"删除原始时间列: {time_col}")
            data = data.drop(columns=[time_col])
        except Exception as e:
            ColorPrinter.print_error(f"时间特征提取失败: {e}")
            ColorPrinter.print_info("跳过时间特征提取")
        
        return data
    #endregion

    #region 高级时间处理
    def high_preprocessor_time(self, data, time_col):
        """提取高级时间特征
        
        Args:
            data: 输入数据
            time_col: 时间列名
            
        Returns:
            处理后的数据
        """
        date_series = data[time_col]
        
        # 为特征列添加时间列前缀，避免多列时间处理时的列名冲突
        prefix = f"{time_col}_"
        
        # 基本高级特征
        data[f'{prefix}weekday'] = date_series.dt.weekday
        data[f'{prefix}quarter'] = date_series.dt.quarter
        data[f'{prefix}is_month_start'] = date_series.dt.is_month_start.astype(int)
        data[f'{prefix}is_month_end'] = date_series.dt.is_month_end.astype(int)
        data[f'{prefix}is_quarter_start'] = date_series.dt.is_quarter_start.astype(int)
        data[f'{prefix}is_quarter_end'] = date_series.dt.is_quarter_end.astype(int)
        
        # 更多时间特征
        data[f'{prefix}is_weekend'] = ((date_series.dt.weekday == 5) | (date_series.dt.weekday == 6)).astype(int)
        data[f'{prefix}day_of_year'] = date_series.dt.dayofyear
        
        # 处理周数特征
        data[f'{prefix}week_of_year'] = date_series.dt.isocalendar().week.astype(int)
        
        # 季节性特征
        # 计算月和日的季节性特征
        months = date_series.dt.month.values.astype(np.float64)
        days = date_series.dt.day.values.astype(np.float64)
        
        # 直接使用numpy向量化操作计算季节性特征
        month_sin = np.sin(2 * np.pi * months / 12)
        month_cos = np.cos(2 * np.pi * months / 12)
        day_sin = np.sin(2 * np.pi * days / 31)
        day_cos = np.cos(2 * np.pi * days / 31)
        
        data[f'{prefix}month_sin'] = month_sin
        data[f'{prefix}month_cos'] = month_cos
        data[f'{prefix}day_sin'] = day_sin
        data[f'{prefix}day_cos'] = day_cos
        
        # 尝试添加小时相关的季节性特征
        try:
            hours = date_series.dt.hour.values.astype(np.float64)
            # 使用numpy向量化操作计算小时季节性特征
            hour_sin = np.sin(2 * np.pi * hours / 24)
            hour_cos = np.cos(2 * np.pi * hours / 24)
            
            data[f'{prefix}hour_sin'] = hour_sin
            data[f'{prefix}hour_cos'] = hour_cos
        except Exception:
            # 如果时间列不包含小时信息，跳过这些特征
            pass
        
        return data
    #endregion


"""
Parameter documentation:

shortcut_time parameter dictionary:
    - time_ways: List of time column processing configurations
      Type: list of dictionaries
      Optional values: List containing time column processing configurations
      Default: None (must be specified)
      Description: Each element in the list is a dictionary with 'time_col' (time column name) and 'time_type' (processing type: 'basic' or 'advance')

Usage example:
    time_params = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'},
            {'time_col': 'timestamp', 'time_type': 'advance'}
        ]
    }
    time_processor = TimePreprocessing(shortcut_time=time_params)
    
    # Process time columns
    processed_data = time_processor(data)
"""


if __name__ == "__main__":
    import pandas as pd
    import numpy as np
    
    print("=" * 60)
    print("时间预处理测试程序")
    print("=" * 60)
    
    # 测试1: 标准日期格式
    print("\n测试1: 标准日期格式")
    dates = pd.date_range(start='2023-01-01', periods=10, freq='D')
    test_data = pd.DataFrame({
        'date': dates,
        'feature1': np.random.randint(1, 100, 10),
        'feature2': np.random.randint(1, 100, 10),
        'label': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
    })
    
    print("\n原始数据:")
    print(test_data)
    print(f"\n数据形状: {test_data.shape}")
    print(f"\n时间列类型: {test_data['date'].dtype}")
    
    # 测试2: 不同时间格式
    print(f"\n{'=' * 60}")
    print("测试2: 不同时间格式")
    
    # 创建包含不同时间格式的测试数据
    different_formats_data = pd.DataFrame({
        'date': [
            '2023-01-01',         # ISO格式
            '01/02/2023',         # 美国格式
            '03.04.2023',         # 欧洲格式
            '2023年05月06日',       # 中文格式
            1672531200,           # 时间戳（秒级）
            1672531200000,        # 时间戳（毫秒级）
            '2023-07-07 12:00:00',  # 带时间的ISO格式
            '08/08/2023 13:30:00',  # 带时间的美国格式
            '09.09.2023 14:45:00',  # 带时间的欧洲格式
            '2023年10月10日 15:00:00' # 带时间的中文格式
        ],
        'feature1': np.random.randint(1, 100, 10),
        'label': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
    })
    
    print("\n不同时间格式数据:")
    print(different_formats_data)
    
    # 测试3: 包含缺失值的时间数据
    print(f"\n{'=' * 60}")
    print("测试3: 包含缺失值的时间数据")
    
    missing_data = pd.DataFrame({
        'date': [
            '2023-01-01',
            None,
            '2023-01-03',
            '2023-01-04',
            None,
            '2023-01-06',
            '2023-01-07',
            None,
            '2023-01-09',
            '2023-01-10'
        ],
        'feature1': np.random.randint(1, 100, 10),
        'label': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
    })
    
    print("\n包含缺失值的时间数据:")
    print(missing_data)
    print(f"\n缺失值数量: {missing_data['date'].isnull().sum()}")
    
    # 测试不同的时间处理方式
    test_cases = [
        {
            'time_type': 'basic',
            'description': '基础时间特征提取'
        },
        {
            'time_type': 'advance',
            'description': '高级时间特征提取'
        }
    ]
    
    # 测试标准日期格式
    print(f"\n{'=' * 60}")
    print("测试标准日期格式处理")
    print('=' * 60)
    
    for i, test_case in enumerate(test_cases, 1):
        print(f"\n{'=' * 60}")
        print(f"测试 {i}: {test_case['description']}")
        print('=' * 60)
        
        time_params = {
            'time_ways': [
                {'time_col': 'date', 'time_type': test_case['time_type']}
            ]
        }
        time_processor = TimePreprocessing(shortcut_time=time_params)
        try:
            processed_data = time_processor(test_data.copy())
            
            print("\n处理后的数据:")
            print(processed_data)
            print(f"\n处理后的数据形状: {processed_data.shape}")
            
            print("\n新增的时间特征:")
            original_cols = set(test_data.columns)
            processed_cols = set(processed_data.columns)
            added_cols = processed_cols - original_cols
            print(f"新增列: {added_cols}")
            
            if test_case['time_type'] == 'advance':
                print("\n高级时间特征统计:")
                for col in ['weekday', 'quarter', 'is_weekend', 'day_of_year', 'week_of_year']:
                    if col in processed_data.columns:
                        print(f"{col}: {processed_data[col].unique()}")
                
                print("\n季节性特征示例:")
                for col in ['month_sin', 'month_cos', 'day_sin', 'day_cos']:
                    if col in processed_data.columns:
                        print(f"{col}: 均值={processed_data[col].mean():.4f}, 标准差={processed_data[col].std():.4f}")
        except Exception as e:
            print(f"\n处理出错: {e}")
    
    # 测试不同时间格式
    print(f"\n{'=' * 60}")
    print("测试不同时间格式处理")
    print('=' * 60)
    
    time_params = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'}
        ]
    }
    time_processor = TimePreprocessing(shortcut_time=time_params)
    try:
        processed_data = time_processor(different_formats_data.copy())
        print("\n处理后的数据:")
        print(processed_data)
        print(f"\n处理后的数据形状: {processed_data.shape}")
        print(f"\n时间列类型: {processed_data['date'].dtype}")
    except Exception as e:
        print(f"\n处理出错: {e}")
    
    # 测试包含缺失值的时间数据
    print(f"\n{'=' * 60}")
    print("测试包含缺失值的时间数据处理")
    print('=' * 60)
    
    time_params = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'}
        ]
    }
    time_processor = TimePreprocessing(shortcut_time=time_params)
    try:
        processed_data = time_processor(missing_data.copy())
        print("\n处理后的数据:")
        print(processed_data)
        print(f"\n处理后的数据形状: {processed_data.shape}")
        print(f"\n处理后缺失值数量: {processed_data['date'].isnull().sum()}")
    except Exception as e:
        print(f"\n处理出错: {e}")
    
    print("\n" + "=" * 60)
    print("测试完成！")
    print("=" * 60)
    
    # 深度渗透测试套件
    print(f"\n{'=' * 80}")
    print("深度渗透测试套件")
    print('=' * 80)
    
    # 创建更大的时间测试数据
    np.random.seed(42)
    dates = pd.date_range(start='2023-01-01', periods=100, freq='D')
    large_time_data = pd.DataFrame({
        'date': dates,
        'date2': pd.date_range(start='2023-03-01', periods=100, freq='h'),
        'feature1': np.random.randint(1, 100, 100),
        'feature2': np.random.normal(50, 10, 100),
        'label': ['A'] * 50 + ['B'] * 50
    })
    
    # 测试1: 边界条件测试 - 空参数
    print(f"\n{'-' * 60}")
    print("测试1: 边界条件测试 - 空参数")
    print('-' * 60)
    
    time_processor_1 = TimePreprocessing(shortcut_time={})
    try:
        result_1 = time_processor_1(large_time_data.copy())
        print(f"\n数据形状变化: {large_time_data.shape} -> {result_1.shape}")
        print("期望：数据保持不变")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试2: 边界条件测试 - 不存在的时间列
    print(f"\n{'-' * 60}")
    print("测试2: 边界条件测试 - 不存在的时间列")
    print('-' * 60)
    
    no_time_data = pd.DataFrame({
        'feature1': np.random.randint(1, 100, 100),
        'feature2': np.random.normal(50, 10, 100),
        'label': ['A'] * 50 + ['B'] * 50
    })
    
    params_nonexistent = {
        'time_ways': [
            {'time_col': 'nonexistent_date', 'time_type': 'basic'}
        ]
    }
    time_processor_2 = TimePreprocessing(shortcut_time=params_nonexistent)
    try:
        result_2 = time_processor_2(no_time_data.copy())
        print(f"\n数据形状变化: {no_time_data.shape} -> {result_2.shape}")
        print("期望：数据保持不变")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试3: 边界条件测试 - 空数据
    print(f"\n{'-' * 60}")
    print("测试3: 边界条件测试 - 空数据")
    print('-' * 60)
    
    empty_data = pd.DataFrame({
        'date': [],
        'feature1': [],
        'label': []
    })
    
    params_empty = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'}
        ]
    }
    time_processor_3 = TimePreprocessing(shortcut_time=params_empty)
    try:
        result_3 = time_processor_3(empty_data.copy())
        print(f"\n数据形状变化: {empty_data.shape} -> {result_3.shape}")
        print("期望：空数据保持不变")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试4: 边界条件测试 - 多列时间处理
    print(f"\n{'-' * 60}")
    print("测试4: 边界条件测试 - 多列时间处理")
    print('-' * 60)
    
    params_multi = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'},
            {'time_col': 'date2', 'time_type': 'basic'}
        ]
    }
    time_processor_4 = TimePreprocessing(shortcut_time=params_multi)
    try:
        result_4 = time_processor_4(large_time_data.copy())
        print(f"\n数据形状变化: {large_time_data.shape} -> {result_4.shape}")
        print("期望：两列时间都被处理")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试5: 边界条件测试 - 时间戳为0
    print(f"\n{'-' * 60}")
    print("测试5: 边界条件测试 - 时间戳为0")
    print('-' * 60)
    
    zero_timestamp_data = pd.DataFrame({
        'date': [0, 100, 1000, 10000, 100000],
        'feature1': np.random.randint(1, 100, 5),
        'label': ['A', 'B', 'A', 'B', 'A']
    })
    
    params_zero = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'}
        ]
    }
    time_processor_5 = TimePreprocessing(shortcut_time=params_zero)
    try:
        result_5 = time_processor_5(zero_timestamp_data.copy())
        print(f"\n数据形状变化: {zero_timestamp_data.shape} -> {result_5.shape}")
        print("期望：处理应该正常进行")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试6: 边界条件测试 - 未来时间
    print(f"\n{'-' * 60}")
    print("测试6: 边界条件测试 - 未来时间")
    print('-' * 60)
    
    future_dates = pd.date_range(start='2050-01-01', periods=10, freq='D')
    future_data = pd.DataFrame({
        'date': future_dates,
        'feature1': np.random.randint(1, 100, 10),
        'label': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
    })
    
    params_future = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'basic'}
        ]
    }
    time_processor_6 = TimePreprocessing(shortcut_time=params_future)
    try:
        result_6 = time_processor_6(future_data.copy())
        print(f"\n数据形状变化: {future_data.shape} -> {result_6.shape}")
        print("期望：处理应该正常进行")
    except Exception as e:
        print(f"处理出错: {e}")
    
    # 测试7: 边界条件测试 - 所有时间类型
    print(f"\n{'-' * 60}")
    print("测试7: 边界条件测试 - 所有时间类型")
    print('-' * 60)
    
    time_types = ['basic', 'advance']
    
    for tt in time_types:
        time_params = {
            'time_ways': [
                {'time_col': 'date', 'time_type': tt}
            ]
        }
        time_processor = TimePreprocessing(shortcut_time=time_params)
        try:
            result = time_processor(large_time_data.copy())
            print(f"\n时间类型 {tt}:")
            print(f"  数据形状变化: {large_time_data.shape} -> {result.shape}")
        except Exception as e:
            print(f"\n时间类型 {tt} 出错: {e}")
    
    # 测试8: 验证结果
    print(f"\n{'-' * 60}")
    print("测试8: 验证结果")
    print('-' * 60)
    
    verify_dates = pd.date_range(start='2023-01-01', periods=10, freq='D')
    verify_data = pd.DataFrame({
        'date': verify_dates,
        'feature1': np.random.randint(1, 100, 10),
        'label': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
    })
    
    params_verify = {
        'time_ways': [
            {'time_col': 'date', 'time_type': 'advance'}
        ]
    }
    time_processor_verify = TimePreprocessing(shortcut_time=params_verify)
    try:
        result_verify = time_processor_verify(verify_data.copy())
        print(f"\n原始数据形状: {verify_data.shape}")
        print(f"处理后数据形状: {result_verify.shape}")
        print(f"新增列数: {result_verify.shape[1] - verify_data.shape[1]}")
        print("期望：成功提取时间特征")
    except Exception as e:
        print(f"处理出错: {e}")
    
    print(f"\n{'=' * 80}")
    print("深度渗透测试完成！")
    print('=' * 80)