from .... import logger,fitz,BytesIO,sys
from .nlp_Processor import SpacyNLP,NLTKNLP

class PDFProcessor:
    """
    PDF文件处理器，用于解析PDF文件并处理每一页的内容。

    Attributes:
        file_content (BytesIO): PDF文件的内容。
        document_id (str): 文档的唯一标识符。
        max_tokens (int): 处理文本时的最大令牌数限制。
        bucket_name (str): 用于存储处理结果的存储桶名称。
        KbmService: KbmService对象，用于提供文本处理和存储服务。

    Methods:
        process_pdf(): 解析PDF文件并处理每一页的内容，包括文本和图片。
    """

    def __init__(self, nlp_type=1):
        """
        初始化PDF处理器，根据指定的NLP类型选择合适的NLP处理器。

        Args:
            nlp_type (int, optional): 指定NLP处理器的类型。1为SpacyNLP，2为NLTKNLP。默认为1。
        """
        
        # self.nlp = SpacyNLP() if nlp_type == 1 else NLTKNLP() if nlp_type == 2 else None
        self.nlp = SpacyNLP()
       

    def get_results(self, file_content, document_id, max_tokens, bucket_name, KbmService):
        """
        解析PDF文件并处理每一页的内容，包括文本和图片。

        Args:
            file_content (BytesIO): PDF文件的内容。
            document_id (str): 文档的ID。
            max_tokens (int): 最大令牌数。
            bucket_name (str): 存储桶的名称。
            KbmService: KbmService对象。

        Returns:
            tuple: 包含处理后的句子列表和页面图片列表的元组。
        """

        self.file_content = file_content
        self.document_id = document_id
        self.max_tokens = max_tokens
        self.bucket_name = bucket_name
        self.KbmService = KbmService    
        # 初始化日志信息，表示开始解析PDF
        sentences = None
        logger.info("开始解析pdf")
        processed_pages, current_pages = self._process_pdf()  # 解析PDF文件并处理每一页的内容
        try:
            sentences = self._split_sentences(processed_pages,max_tokens)  # 将处理后的页面列表分割成句子列表
        except Exception as e:
            logger.error(f"错误{str(e)}")
            
        logger.info('PDFProcessor处理完成')
        return sentences, current_pages
       
    def _process_pdf(self):
        """
        解析PDF文件并处理每一页的内容。

        Returns:
            list: 处理后的页面列表。
        """
        processed_pages = []  # 初始化处理后的页面列表
        current_pages =[]
        pdf_reader = None
        try:
            # 检查文件内容是否为BytesIO对象
            if isinstance(self.file_content, BytesIO):
                # 如果是BytesIO对象，则打开PDF文件
                pdf_reader = fitz.open(stream=self.file_content, filetype="pdf")
            else:
                # 如果不是BytesIO对象，则抛出ValueError异常
                raise ValueError(f"文件内容不是BytesIO对象。类型：{type(self.file_content)}")
        except Exception as e:
            # 如果在打开PDF时发生异常，则记录错误日志并返回空列表
            logger.error(f"打开PDF失败：{str(e)}")
            raise ValueError(f"打开PDF失败：{str(e)} {sys._getframe().f_lineno}")

        # 遍历PDF中的每一页
        for page_index in range(len(pdf_reader)):
            current_page = pdf_reader[page_index]                           # 获取当前页
            page_imag = self._process_page_images(current_page)             # 处理页面图片
            page_text = self._extract_page_text(current_page, pdf_reader)   # 提取当前页的文本内容
            processed_pages.append(page_text)                               # 将当前页的文本内容添加到处理后的页面列表中
            current_pages.append(page_imag)
        pdf_reader.close()
        return processed_pages,current_pages
    
    def  _extract_page_text(self, page, pdf_reader):
        """
        提取PDF页面的文本内容。

        Args:
            page (fitz.Page): 需要提取文本的PDF页面对象。
            pdf_reader (fitz.Document): PDF文件的阅读器对象。

        Returns:
            str: 页面的文本内容。
        """
        page_text = page.get_text()  # 获取页面的文本内容
        for image_info in page.get_images():
            image_xref = image_info[0]  # 获取图片的引用
            extracted_image = pdf_reader.extract_image(image_xref)  # 提取图片
            raw_image_data = extracted_image["image"]  # 获取图片的raw数据
            if isinstance(raw_image_data, bytes):
                extracted_text = self.KbmService.extract_text_from_image(raw_image_data)  # 从图片中提取文本
                if extracted_text and len(extracted_text) > 5:
                    page_text += extracted_text
        return page_text
    
    def _process_page_images(self, processed_pages):
        """
        处理页面图片，渲染页面为图像，保存到MinIO，并记录图像名称。

        Args:
            processed_pages (list): 处理后的页面列表。

        Returns:
            list: 包含页面号和图像名称的元组列表。
        """
        page_images =[]
        
        try:
            # 遍历处理后的页面列表
            page_image = self.KbmService.render_page_to_image(processed_pages)
            # 保存图像到MinIO，并获取图像名称
            image_name = self.KbmService.save_image_to_minio(page_image, self.bucket_name)
            # 将页面号和图像名称作为元组添加到page_images列表中
            page_images.append(image_name)
        except Exception as e:
            logger.error(f'错误')

        # 返回包含所有页面图像信息的列表
        return page_images
    
    def _split_sentences(self, processed_pages,cmax_tokens=250):
        """
        使用NLP将处理后的内容分割成句子。

        Args:
            processed_pages (list): 处理后的页面列表。

        Returns:
            list: 包含分割后的句子的列表。
        """
        # 初始化一个空列表，用于存储分割后的句子
        sentence_list = []
        # 遍历处理后的页面列表
        for page_text in processed_pages:
            # 使用SNLP模型处理文本，
            sentence_list.append( self.nlp.split_text_into_chunks(page_text,cmax_tokens))
        # 返回包含所有分割后的句子的列表
        return sentence_list
