import utils, pandas as pd, os, json
from pathlib import Path

from models.project_data import SubProjectModel, SubProjectItemModel
from stores.project_store import ProjectStore
from ai.fast_gpt import FastGPTAi

class PreProcess:

    def __init__(self):
        self._logger= utils.get_logger()
        self._project_store= ProjectStore()
        # self._ai = utils.AiHelper()
        self._ai = FastGPTAi()
        self._ai_sys_prompt = "从给定信息中提取结构化信息，并返回json压缩成一行的字符串，如果部分信息为空或nan，则该字段返回为空。"
        self.separate_ai_calls = False
        self._data={}

    def run(self, project: SubProjectModel, separate_ai_calls=True) ->bool:
        try:
            if not project.file_paths:
                return False
            self._logger.info(f"开始预处理项目：{project.sub_project_name}[{project.project_id}_{project.standard_version}] ")
            self._project_store.update_sub_project_status(project.id, 21)
            self.separate_ai_calls = separate_ai_calls
            res_data = []
            raw_data = self.read_excels(project.file_paths)
            if self.separate_ai_calls:
                for filename, sheets in raw_data.items():
                    excel_data = self.normalize_data({filename: sheets})
                    data = self.call_ai(project.id, excel_data)
                    res_data.extend(data)
            else:
                excel_data = self.normalize_data(raw_data)
                res_data = self.call_ai(project.id, excel_data)
            project.items = res_data
            self._project_store.re_insert_sub_project(project)
            self._logger.info(f"结束预处理项目：{project.sub_project_name}[{project.project_id}_{project.standard_version}] [设备条数：{len(project.items)}]")
            self._project_store.update_sub_project_status(project.id, 31)
            return True
        except Exception as e:
            self._logger.error(f"预处理项目失败：[{project.project_id}] 错误： {e}")
            self._project_store.update_sub_project_status(project.id, 11)
            return False

    def read_excels(self, paths):
        file_paths = paths.split(',')
        raw_data = {}
        for file in file_paths:
            try:
                file = Path(file)  # 将 file 转换为 Path 对象
                if not file.exists():
                    self._logger.error(f"文件不存在：{file}")
                    continue
                # 使用确定的表头行读取整个 Excel 文件
                # 读取所有sheet
                sheets = pd.read_excel(file, sheet_name=None)
                sheet_data = {}
                for sheet_name, df in sheets.items():
                    # 读取前几行以确定表头
                    header_row = self.determine_header_row(df, file.name)
                    if header_row >= 0:
                        # 使用确定的表头行重新读取Sheet
                        df = df.iloc[header_row:]  # 直接使用确定的表头行
                        df.columns = df.iloc[0]  # 设置表头
                        df = df[1:]  # 去掉表头行
                        df.reset_index(drop=True, inplace=True)  # 重置索引
                    sheet_data[sheet_name] = df
                raw_data[file.name] = sheet_data
                self._logger.debug(f"读取 {file.name} 的 {len(sheet_data)} 个sheet")
            except Exception as e:
                self._logger.error(f"读取 {file.name} 失败: {e}")
        return raw_data


    def read_excels_1(self, folder_path):
        path = Path(folder_path)
        # 验证路径是否存在
        if not path.exists():
            raise FileNotFoundError(f"目录不存在: {path.resolve()}")

        # 验证是否是目录
        if not path.is_dir():
            raise NotADirectoryError(f"路径不是目录: {path.resolve()}")

        excel_files = list(path.glob('*'))

        if not excel_files:
            self._logger.warning(f"警告：未找到任何文件")
        raw_data = {}
        for file in excel_files:
            try:
                # 使用确定的表头行读取整个 Excel 文件
                # 读取所有sheet
                sheets = pd.read_excel(file, sheet_name=None)
                sheet_data = {}
                for sheet_name, df in sheets.items():
                    # 读取前几行以确定表头
                    header_row = self.determine_header_row(df, file.name)
                    if header_row >= 0:
                        # 使用确定的表头行重新读取Sheet
                        df = df.iloc[header_row:]  # 直接使用确定的表头行
                        df.columns = df.iloc[0]  # 设置表头
                        df = df[1:]  # 去掉表头行
                        df.reset_index(drop=True, inplace=True)  # 重置索引
                    sheet_data[sheet_name] = df
                raw_data[file.name] = sheet_data
                self._logger.debug(f"读取 {file.name} 的 {len(sheet_data)} 个sheet")
            except Exception as e:
                self._logger.error(f"读取 {file.name} 失败: {e}")
        return raw_data

    def determine_header_row(self, df,file_name):
        if any('序号' in str(cell) or 'No.' in str(cell) for cell in df.head()):
            self._logger.debug(f"{file_name}表头包含“序号”")
            return -1
        for i, row in df.iterrows():
            if any('序号' in str(cell) or 'No.' in str(cell) for cell in row):
                self._logger.debug(f"{file_name}找到包含“序号”的行：{i}")
                return i
        # 如果没有找到包含“序号”的行，默认使用第0行作为表头
        self._logger.warning(f"{file_name}未找到包含“序号”的行，使用默认的第1行作为表头")
        return -1
    @staticmethod
    def normalize_data(raw_data):
        excel_data = []
        for filename, sheets in raw_data.items():
            for sheet_name, df in sheets.items():
                # 统一编码/去除空行等
                df = df.map(lambda x: x.strip() if isinstance(x, str) else x)
                # df.columns = ['名称', '型号规格','单位']
                # 去除空行
                df = df.dropna(how='all')
                # 去除空行 及 型号规格为空
                # df = df.dropna(subset=['型号规格'], how='any')
                excel_data.append({
                    "filename": filename,
                    "sheet": sheet_name,
                    # "data": df.to_dict(orient='records')
                    "data": df.to_markdown()
                })
        return excel_data

    @staticmethod
    def prompt_template(excel_data):
        prompt = """
        请从以下表格数据中提取结构化信息，要求:
        1. 识别字段类型：数值/文本/日期
        2. 提取结构化信息:```typescript
        export interface device { 
        n: string; //物料名称
        m: string; //型号规格
        u：string; //单位
        c: float; //数量
        }
        ```
        3. 返回结构体device的数组的json数组格式，压缩成一行
        """
        prompt += "数据记录：\n"
        for data in excel_data:
            # for row in data['data']:
            #     prompt += f"{row}\n"
            prompt += f"{data['data']}\n"
        print("AI_PROMPT: " + prompt)
        return prompt

    def call_ai(self, project_id:int, excel_data):
        # api_key = utils.get_config_value("fastgpt.api_key_pre_process")
        # prompt = self.prompt_template(excel_data)
        # json_data = self._ai.call_ai(prompt, api_key)
        json_data = [{'n': 'D型梁使用', 'm': '每使用1季度跨度(m)12', 'u': '孔', 'c': 1082.0}, {'n': 'D型梁使用', 'm': '每使用1季度跨度(m)16', 'u': '孔', 'c': 1082.0}, {'n': 'D型梁使用', 'm': '每使用1季度跨度(m)20', 'u': '孔', 'c': 1082.0}, {'n': 'D型梁使用', 'm': '每使用1季度跨度(m)24', 'u': '孔', 'c': 1082.0}]
        data = self.format_data(project_id, json_data)
        return data

    def format_data(self, project_id, data_list) ->list[SubProjectItemModel]:
        formatted_list = []
        for data in data_list:
            try:
                item = SubProjectItemModel(
                    sub_project_id=project_id,
                    device_name="",
                    device_model="",
                    device_unit="",
                )
                if data.get('n'):
                    item.device_name = data['n']
                if data.get('m'):
                    item.device_model = data['m']
                if data.get('u'):
                    item.device_unit = data['u']
                if data.get('c'):
                    item.device_count = data['c']
                formatted_list.append(item)
            except Exception as e:
                self._logger.error(f"格式化数据时出错: {data} {e}")
        self._logger.debug(f"格式化数据数量: {len(formatted_list)}")
        return formatted_list

    def run_1(self, sub_project: SubProjectModel) ->bool:
        self._logger.info(f"开始预处理项目：{sub_project.sub_project_name}[{sub_project.project_id}_{sub_project.standard_version}] ")
        base_path=  utils.get_config_value("file.source_path", "./temp_files")
        folder_path= os.path.join(base_path, f'{sub_project.get_path()}')
        path = Path(folder_path)
        # 验证路径是否存在
        if not path.exists():
            raise FileNotFoundError(f"目录不存在: {path.resolve()}")

        # 验证是否是目录
        if not path.is_dir():
            raise NotADirectoryError(f"路径不是目录: {path.resolve()}")

        excel_files = list(path.glob('*'))

        if not excel_files:
            self._logger.warning(f"警告：未找到任何文件")
            raise FileNotFoundError(f"未找到任何文件")
        try:
            self._project_store.update_sub_project_status(sub_project.id, 21)
            items =[]
            for file in excel_files:
                file_path = str(file.resolve())
                data = self.call_ai_with_files(sub_project.id, file_path)
                if data:
                    items.extend(data)
            sub_project.items = items
            self._project_store.re_insert_sub_project(sub_project)
            self._logger.info(
                f"结束预处理项目：{sub_project.sub_project_name}[{sub_project.project_id}_{sub_project.standard_version}] [设备条数：{len(sub_project.items)}]")
            self._project_store.update_sub_project_status(sub_project.id, 31)
            return True
        except Exception as e:
            self._logger.error(f"项目：{sub_project.project_id} 文件处理失败: {e}")
            self._project_store.update_sub_project_status(sub_project.id, 11)
            return False


    def call_ai_with_files(self, sub_id:int,file_paths:str) ->json:
        try:
            prompt = """从上传的表格数据中提取信息，要求:
                       1. 识别字段类型：数值/文本/日期
                       2. 提取信息结构体:```typescript
                           type item { 
                               n: string; //物料名称
                               m: string; //型号规格
                               u：string; //单位
                               c: float; //数量,数量多列的话要求和
                           }
                       ```
                       3. 返回压缩成一行的item数组的json字符串
                       """
            api_key = utils.get_config_value("fastgpt.api_key_pre_process")
            data = self._ai.call_ai_with_file(file_paths, prompt, api_key)
            if isinstance(data, str):
                data = json.loads(data)
            res_data = self.format_data(sub_id, data)
            return res_data
        except Exception as e:
            self._logger.error(f"文件处理失败: {e}")
            return ""

    @staticmethod
    def check_file_type(file_name:str) ->bool:
        file_type = file_name.split('.')[-1]
        if file_type not in ['xlsx','xls']:
            return False
        return True