"""
通用供应商处理器

可配置化的供应商处理器，支持通过配置文件定义处理规则
"""

import fnmatch
import pandas as pd
from typing import Optional, Dict, Any, List
from pathlib import Path

from app.core.processors.base import BaseProcessor
from app.core.utils.log_utils import get_logger
from app.core.handlers.rule_engine import apply_rules
from app.core.handlers.column_mapper import ColumnMapper
from app.core.handlers.data_cleaner import DataCleaner
from app.core.handlers.calculator import DataCalculator

logger = get_logger(__name__)


class GenericSupplierProcessor(BaseProcessor):
    """通用供应商处理器
    
    基于配置文件处理不同供应商的Excel文件，支持：
    - 文件名模式匹配
    - 内容特征识别
    - 列映射配置
    - 数据清洗规则
    - 计算处理规则
    """
    
    def __init__(self, config: Dict[str, Any], supplier_config: Dict[str, Any]):
        """初始化通用供应商处理器
        
        Args:
            config: 系统配置
            supplier_config: 供应商特定配置
        """
        super().__init__(config)
        self.supplier_config = supplier_config
        
        # 从配置中提取基本信息
        self.name = supplier_config.get('name', 'GenericSupplier')
        self.description = supplier_config.get('description', '通用供应商处理器')
        
        # 处理规则配置
        self.filename_patterns = supplier_config.get('filename_patterns', [])
        self.content_indicators = supplier_config.get('content_indicators', [])
        self.column_mapping = supplier_config.get('column_mapping', {})
        self.cleaning_rules = supplier_config.get('cleaning_rules', [])
        self.calculations = supplier_config.get('calculations', [])
        
        # 输出配置
        self.output_template = supplier_config.get('output_template', 'templates/银豹-采购单模板.xls')
        self.output_suffix = supplier_config.get('output_suffix', '_银豹采购单')
    
    def can_process(self, file_path: Path) -> bool:
        """判断是否能处理该文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否能处理
        """
        if not self.validate_input(file_path):
            return False
        
        # 检查文件名模式
        if self.filename_patterns:
            filename_match = self._check_filename_patterns(file_path)
            if filename_match:
                return True
        
        # 检查文件内容特征
        if self.content_indicators:
            content_match = self._check_content_indicators(file_path)
            if content_match:
                return True
        
        # 如果都没有配置，则无法判断
        if not self.filename_patterns and not self.content_indicators:
            self.logger.warning(f"处理器 {self.name} 没有配置识别规则")
            return False
        
        return False
    
    def process(self, input_file: Path, output_dir: Path) -> Optional[Path]:
        """处理文件
        
        Args:
            input_file: 输入文件路径
            output_dir: 输出目录路径
            
        Returns:
            输出文件路径，处理失败返回None
        """
        self.log_processing_start(input_file)
        
        try:
            # 步骤1: 读取数据
            self.logger.info("步骤1/4: 读取数据...")
            df = self._read_supplier_data(input_file)
            if df is None or df.empty:
                self.logger.error("读取数据失败或数据为空")
                self.log_processing_end(input_file, success=False)
                return None
            
            # 步骤2: 应用列映射
            self.logger.info("步骤2/4: 应用列映射...")
            mapped_df = self._apply_column_mapping(df)
            if mapped_df is None:
                self.logger.error("列映射失败")
                self.log_processing_end(input_file, success=False)
                return None
            
            # 步骤3: 数据清洗
            self.logger.info("步骤3/4: 数据清洗...")
            cleaned_df = self._apply_data_cleaning(mapped_df)
            if cleaned_df is None:
                self.logger.error("数据清洗失败")
                self.log_processing_end(input_file, success=False)
                return None
            try:
                rules = self.supplier_config.get('rules', [])
                dictionary = self.supplier_config.get('dictionary')
                standardized_df = apply_rules(cleaned_df, rules, dictionary)
            except Exception as e:
                self.logger.warning(f"规则执行失败: {e}")
                standardized_df = cleaned_df
            
            # 步骤4: 计算处理
            self.logger.info("步骤4/4: 计算处理...")
            calculated_df = self._apply_calculations(standardized_df)
            if calculated_df is None:
                self.logger.error("计算处理失败")
                self.log_processing_end(input_file, success=False)
                return None
            
            # 生成输出文件
            output_file = self._generate_output(calculated_df, input_file, output_dir)
            
            if output_file and output_file.exists():
                self.logger.info(f"处理完成，输出文件: {output_file}")
                self.log_processing_end(input_file, output_file, success=True)
                return output_file
            else:
                self.logger.error("输出文件生成失败")
                self.log_processing_end(input_file, success=False)
                return None
                
        except Exception as e:
            self.logger.error(f"处理文件时出错: {e}", exc_info=True)
            self.log_processing_end(input_file, success=False)
            return None
    
    def get_required_columns(self) -> List[str]:
        """返回需要的列名列表"""
        # 从列映射配置中提取目标列名
        return list(self.column_mapping.values()) if self.column_mapping else []
    
    def _check_filename_patterns(self, file_path: Path) -> bool:
        """检查文件名模式
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否匹配
        """
        try:
            filename = file_path.name
            for pattern in self.filename_patterns:
                if fnmatch.fnmatch(filename.lower(), pattern.lower()):
                    self.logger.info(f"文件名匹配成功: {filename} -> {pattern}")
                    return True
            return False
        except Exception as e:
            self.logger.error(f"检查文件名模式时出错: {e}")
            return False
    
    def _check_content_indicators(self, file_path: Path) -> bool:
        """检查文件内容特征
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否匹配
        """
        try:
            df = self._read_excel_safely(file_path, nrows=5)
            
            # 检查列名中是否包含指定关键词
            columns_str = str(list(df.columns)).lower()
            
            for indicator in self.content_indicators:
                if indicator.lower() in columns_str:
                    self.logger.info(f"内容特征匹配成功: {indicator}")
                    return True
            
            return False
            
        except Exception as e:
            self.logger.error(f"检查内容特征时出错: {e}")
            return False
    
    def _read_supplier_data(self, file_path: Path) -> Optional[pd.DataFrame]:
        """读取供应商数据
        
        Args:
            file_path: 文件路径
            
        Returns:
            数据DataFrame或None
        """
        try:
            specified = self.supplier_config.get('header_row')
            if specified is not None:
                try:
                    df = self._read_excel_safely(file_path, header=int(specified))
                except Exception:
                    df = self._read_excel_safely(file_path)
            else:
                df0 = self._read_excel_safely(file_path, header=None)
                if df0 is None:
                    return None
                header_row = self._find_header_row(df0)
                if header_row is not None:
                    df = self._read_excel_safely(file_path, header=header_row)
                else:
                    df = self._read_excel_safely(file_path)
            if df is None or df.empty:
                self.logger.warning("数据文件为空")
                return None
            self.logger.info(f"成功读取数据，形状: {df.shape}")
            return df
        except Exception as e:
            self.logger.error(f"读取数据失败: {e}")
            return None

    def _find_header_row(self, df: pd.DataFrame) -> Optional[int]:
        result = ColumnMapper.detect_header_row(df, max_rows=30)
        return result if result >= 0 else None
    
    def _apply_column_mapping(self, df: pd.DataFrame) -> Optional[pd.DataFrame]:
        """应用列映射
        
        Args:
            df: 原始数据
            
        Returns:
            映射后的数据或None
        """
        if not self.column_mapping:
            self.logger.info("没有列映射配置")
            return df
        
        try:
            # 应用列重命名
            df_renamed = df.rename(columns=self.column_mapping)
            
            # 检查必需的列是否存在
            required_columns = self.get_required_columns()
            missing_columns = [col for col in required_columns if col not in df_renamed.columns]
            
            if missing_columns:
                self.logger.warning(f"缺少必需的列: {missing_columns}")
                # 创建缺失的列并填充默认值
                for col in missing_columns:
                    df_renamed[col] = 0 if '量' in col or '价' in col else ''
                    self.logger.info(f"创建缺失列: {col}，默认值: {df_renamed[col].iloc[0] if len(df_renamed) > 0 else 'N/A'}")
            
            self.logger.info(f"列映射完成，列名: {list(df_renamed.columns)}")
            return df_renamed
            
        except Exception as e:
            self.logger.error(f"列映射失败: {e}")
            return None
    
    def _apply_data_cleaning(self, df: pd.DataFrame) -> Optional[pd.DataFrame]:
        """应用数据清洗规则，委托给 DataCleaner"""
        if not self.cleaning_rules:
            self.logger.info("没有数据清洗规则")
            return df
        try:
            cleaner = DataCleaner()
            for rule in self.cleaning_rules:
                cleaner.add_rule(rule.get('type'), **{k: v for k, v in rule.items() if k != 'type'})
            result = cleaner.clean(df)
            self.logger.info(f"数据清洗完成，数据形状: {result.shape}")
            return result
        except Exception as e:
            self.logger.error(f"数据清洗失败: {e}")
            return None
    
    def _apply_calculations(self, df: pd.DataFrame) -> Optional[pd.DataFrame]:
        """应用计算处理，委托给 DataCalculator"""
        if not self.calculations:
            self.logger.info("没有计算规则")
            return df
        try:
            calculator = DataCalculator()
            for calc in self.calculations:
                calculator.add_rule(calc.get('type'), **{k: v for k, v in calc.items() if k != 'type'})
            result = calculator.calculate(df)
            self.logger.info(f"计算处理完成，数据形状: {result.shape}")
            return result
        except Exception as e:
            self.logger.error(f"计算处理失败: {e}")
            return None
    
    def _generate_output(self, df: pd.DataFrame, input_file: Path, output_dir: Path) -> Optional[Path]:
        """生成输出文件
        
        Args:
            df: 最终数据
            input_file: 输入文件路径
            output_dir: 输出目录
            
        Returns:
            输出文件路径或None
        """
        try:
            # 生成输出文件名
            timestamp = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S")
            output_filename = f"{input_file.stem}{self.output_suffix}_{timestamp}.xls"
            output_file = output_dir / output_filename
            
            # 这里应该使用实际的模板生成逻辑
            # 暂时直接保存为Excel文件
            df.to_excel(output_file, index=False)
            
            self.logger.info(f"输出文件生成成功: {output_file}")
            return output_file
            
        except Exception as e:
            self.logger.error(f"生成输出文件失败: {e}")
            return None
