"""基于 lxml 的 DOCX 到 XML 格式转换器"""

from typing import Any, Optional, Dict, List
from hos_m2f.converters.base_converter import BaseConverter
from docx import Document
import io
import os
from lxml import etree as ET


class DOCXToXMLLXMLConverter(BaseConverter):
    """基于 lxml 的 DOCX 到 XML 格式转换器"""
    
    def convert(self, input_content: bytes, options: Optional[Dict[str, Any]] = None) -> bytes:
        """将 DOCX 转换为 XML
        
        Args:
            input_content: DOCX 文件的二进制数据
            options: 转换选项
                - include_metadata: 是否包含元数据
                - include_structure: 是否包含文档结构
                - include_formatting: 是否包含格式信息
                - xml_structure: XML 结构配置
                - schema_path: XML Schema 文件路径
                - validate: 是否验证 XML
                
        Returns:
            bytes: XML 文件的二进制数据
        """
        if options is None:
            options = {}
        
        # 加载 DOCX 文档
        doc = Document(io.BytesIO(input_content))
        
        # 转换为 XML
        xml_root = self._docx_to_xml(doc, options)
        
        # 验证 XML
        validate = options.get('validate', False)
        schema_path = options.get('schema_path', None)
        if validate and schema_path:
            validation_result = self._validate_xml(xml_root, schema_path)
            if not validation_result['valid']:
                # 如果验证失败，抛出异常
                error_messages = [f"Line {err['line']}: {err['message']}" for err in validation_result['errors']]
                error_msg = "\n".join(error_messages)
                raise Exception(f"XML validation failed:\n{error_msg}")
        
        # 生成 XML 字符串
        xml_string = ET.tostring(
            xml_root, 
            pretty_print=True, 
            encoding="UTF-8",
            xml_declaration=True
        )
        
        return xml_string
    
    def _validate_xml(self, xml_root: ET.Element, schema_path: str) -> Dict[str, Any]:
        """验证 XML 是否符合指定的 Schema
        
        Args:
            xml_root: XML 根元素
            schema_path: XML Schema 文件路径
            
        Returns:
            Dict[str, Any]: 验证结果
                - valid: bool 是否验证成功
                - errors: list 错误信息列表
                - message: str 验证消息
            
        Raises:
            Exception: 如果验证过程中发生严重错误
        """
        print(f"验证 XML 是否符合 Schema: {schema_path}")
        
        try:
            # 加载 Schema
            schema_doc = ET.parse(schema_path)
            schema = ET.XMLSchema(schema_doc)
            
            # 验证 XML
            try:
                schema.assertValid(xml_root)
                print("XML 验证成功！")
                return {
                    'valid': True,
                    'errors': [],
                    'message': 'XML validation successful'
                }
            except ET.DocumentInvalid as e:
                # 提取详细错误信息
                errors = []
                for error in schema.error_log:
                    error_info = {
                        'line': error.line,
                        'column': error.column,
                        'message': error.message,
                        'domain': error.domain_name,
                        'type': error.type_name
                    }
                    errors.append(error_info)
                
                print(f"XML 验证失败: {e}")
                return {
                    'valid': False,
                    'errors': errors,
                    'message': f'XML validation failed: {str(e)}'
                }
        except Exception as e:
            print(f"验证过程中发生错误: {e}")
            raise
    
    def _docx_to_xml(self, doc: Document, options: Dict[str, Any]) -> ET.Element:
        """将 DOCX 文档转换为 XML 结构
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
            
        Returns:
            ET.Element: XML 根元素
        """
        # 获取选项
        include_metadata = options.get('include_metadata', True)
        include_structure = options.get('include_structure', True)
        include_formatting = options.get('include_formatting', True)
        xml_structure = options.get('xml_structure', 'default')
        
        # 根据指定的 XML 结构创建根元素
        if xml_structure == 'docbook':
            root = self._create_docbook_structure(doc, options)
        elif xml_structure == 'tei':
            root = self._create_tei_structure(doc, options)
        else:
            # 默认结构
            root = self._create_default_structure(doc, options)
        
        return root
    
    def _create_default_structure(self, doc: Document, options: Dict[str, Any]) -> ET.Element:
        """创建默认 XML 结构
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
            
        Returns:
            ET.Element: XML 根元素
        """
        include_metadata = options.get('include_metadata', True)
        include_structure = options.get('include_structure', True)
        include_formatting = options.get('include_formatting', True)
        
        # 创建根元素
        root = ET.Element('document')
        
        # 添加元数据
        if include_metadata:
            metadata_elem = self._extract_metadata(doc)
            if metadata_elem is not None:
                root.append(metadata_elem)
        
        # 添加文档结构
        if include_structure:
            structure_elem = self._extract_structure(doc)
            if structure_elem is not None:
                root.append(structure_elem)
        
        # 添加内容
        content_elem = ET.SubElement(root, 'content')
        self._process_content(doc, content_elem, options)
        
        return root
    
    def _create_docbook_structure(self, doc: Document, options: Dict[str, Any]) -> ET.Element:
        """创建 DocBook XML 结构
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
            
        Returns:
            ET.Element: XML 根元素
        """
        include_metadata = options.get('include_metadata', True)
        include_formatting = options.get('include_formatting', True)
        
        # 创建 DocBook 根元素
        root = ET.Element('article', xmlns='http://docbook.org/ns/docbook', version='5.0')
        
        # 添加元数据
        if include_metadata:
            info_elem = ET.SubElement(root, 'info')
            metadata = self._extract_metadata(doc)
            if metadata is not None:
                # 处理标题
                title_elem = metadata.find('title')
                if title_elem is not None:
                    doc_title_elem = ET.SubElement(info_elem, 'title')
                    doc_title_elem.text = title_elem.text
                
                # 处理作者
                author_elem = metadata.find('author')
                if author_elem is not None:
                    author_info_elem = ET.SubElement(info_elem, 'author')
                    person_elem = ET.SubElement(author_info_elem, 'personname')
                    surname_elem = ET.SubElement(person_elem, 'surname')
                    surname_elem.text = author_elem.text
                
                # 处理创建日期
                created_elem = metadata.find('created')
                if created_elem is not None:
                    date_elem = ET.SubElement(info_elem, 'date', isoformat=created_elem.text)
                    date_elem.text = created_elem.text
                
                # 处理主题
                subject_elem = metadata.find('subject')
                if subject_elem is not None:
                    subject_info_elem = ET.SubElement(info_elem, 'subject')
                    subject_info_elem.text = subject_elem.text
        
        # 添加内容
        body_elem = ET.SubElement(root, 'body')
        self._process_content_docbook(doc, body_elem, options)
        
        return root
    
    def _create_tei_structure(self, doc: Document, options: Dict[str, Any]) -> ET.Element:
        """创建 TEI XML 结构
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
            
        Returns:
            ET.Element: XML 根元素
        """
        include_metadata = options.get('include_metadata', True)
        include_formatting = options.get('include_formatting', True)
        
        # 创建 TEI 根元素
        tei_root = ET.Element('TEI', xmlns='http://www.tei-c.org/ns/1.0')
        
        # 添加 TEI 头部
        tei_header = ET.SubElement(tei_root, 'teiHeader')
        
        # 添加文件描述
        file_desc = ET.SubElement(tei_header, 'fileDesc')
        
        # 添加标题语句
        title_stmt = ET.SubElement(file_desc, 'titleStmt')
        
        # 添加元数据
        if include_metadata:
            metadata = self._extract_metadata(doc)
            if metadata is not None:
                # 处理标题
                title_elem = metadata.find('title')
                if title_elem is not None:
                    doc_title_elem = ET.SubElement(title_stmt, 'title')
                    doc_title_elem.text = title_elem.text
                
                # 处理作者
                author_elem = metadata.find('author')
                if author_elem is not None:
                    doc_author_elem = ET.SubElement(title_stmt, 'author')
                    pers_name_elem = ET.SubElement(doc_author_elem, 'persName')
                    surname_elem = ET.SubElement(pers_name_elem, 'surname')
                    surname_elem.text = author_elem.text
                
                # 处理主题
                subject_elem = metadata.find('subject')
                if subject_elem is not None:
                    subject_info_elem = ET.SubElement(title_stmt, 'note', type='subject')
                    subject_info_elem.text = subject_elem.text
        
        # 添加 publicationStmt
        pub_stmt = ET.SubElement(file_desc, 'publicationStmt')
        publisher_elem = ET.SubElement(pub_stmt, 'publisher')
        publisher_elem.text = 'HOS-M2F Converter'
        pub_date_elem = ET.SubElement(pub_stmt, 'date')
        pub_date_elem.text = '2024'
        
        # 添加 sourceDesc
        source_desc = ET.SubElement(file_desc, 'sourceDesc')
        bibl_elem = ET.SubElement(source_desc, 'bibl')
        bibl_title_elem = ET.SubElement(bibl_elem, 'title')
        bibl_title_elem.text = 'DOCX Document'
        bibl_date_elem = ET.SubElement(bibl_elem, 'date')
        bibl_date_elem.text = '2024'
        
        # 添加 encodingDesc
        encoding_desc = ET.SubElement(tei_header, 'encodingDesc')
        app_info_elem = ET.SubElement(encoding_desc, 'appInfo')
        application_elem = ET.SubElement(app_info_elem, 'application', ident='HOS-M2F', version='1.0')
        application_elem.text = 'DOCX to TEI Converter'
        
        # 添加 profileDesc
        profile_desc = ET.SubElement(tei_header, 'profileDesc')
        text_class_elem = ET.SubElement(profile_desc, 'textClass')
        class_code_elem = ET.SubElement(text_class_elem, 'classCode', scheme='genre')
        class_code_elem.text = 'document'
        
        # 添加 text content
        text_elem = ET.SubElement(tei_root, 'text')
        body_elem = ET.SubElement(text_elem, 'body')
        self._process_content_tei(doc, body_elem, options)
        
        return tei_root
    
    def _process_content_docbook(self, doc: Document, parent_elem: ET.Element, options: Dict[str, Any]) -> None:
        """处理 DocBook 结构的内容
        
        Args:
            doc: DOCX 文档对象
            parent_elem: 父元素
            options: 转换选项
        """
        include_formatting = options.get('include_formatting', True)
        
        # 处理段落
        for i, paragraph in enumerate(doc.paragraphs):
            style_name = paragraph.style.name
            
            if style_name.startswith('Heading '):
                # 处理标题
                level = int(style_name.split(' ')[1])
                if level == 1:
                    section_elem = ET.SubElement(parent_elem, 'section')
                    title_elem = ET.SubElement(section_elem, 'title')
                    title_elem.text = paragraph.text.strip()
                elif level == 2:
                    if parent_elem.tag == 'section':
                        subsection_elem = ET.SubElement(parent_elem, 'section')
                        title_elem = ET.SubElement(subsection_elem, 'title')
                        title_elem.text = paragraph.text.strip()
            else:
                # 处理普通段落
                p_elem = ET.SubElement(parent_elem, 'para')
                p_elem.text = paragraph.text.strip()
        
        # 处理表格
        for i, table in enumerate(doc.tables):
            table_elem = ET.SubElement(parent_elem, 'table')
            tgroup_elem = ET.SubElement(table_elem, 'tgroup', cols=str(len(table.columns)))
            
            # 处理表头
            thead_elem = ET.SubElement(tgroup_elem, 'thead')
            row_elem = ET.SubElement(thead_elem, 'row')
            for cell in table.rows[0].cells:
                entry_elem = ET.SubElement(row_elem, 'entry')
                entry_elem.text = cell.text.strip()
            
            # 处理表格体
            tbody_elem = ET.SubElement(tgroup_elem, 'tbody')
            for row in table.rows[1:]:
                row_elem = ET.SubElement(tbody_elem, 'row')
                for cell in row.cells:
                    entry_elem = ET.SubElement(row_elem, 'entry')
                    entry_elem.text = cell.text.strip()
    
    def _process_content_tei(self, doc: Document, parent_elem: ET.Element, options: Dict[str, Any]) -> None:
        """处理 TEI 结构的内容
        
        Args:
            doc: DOCX 文档对象
            parent_elem: 父元素
            options: 转换选项
        """
        include_formatting = options.get('include_formatting', True)
        
        # 处理段落
        for i, paragraph in enumerate(doc.paragraphs):
            style_name = paragraph.style.name
            
            if style_name.startswith('Heading '):
                # 处理标题
                level = int(style_name.split(' ')[1])
                head_elem = ET.SubElement(parent_elem, 'head')
                head_elem.text = paragraph.text.strip()
            elif style_name.startswith('List '):
                # 处理列表
                list_type = "ordered" if style_name.startswith('List Number') else "unordered"
                list_elem = ET.SubElement(parent_elem, 'list')
                item_elem = ET.SubElement(list_elem, 'item')
                p_elem = ET.SubElement(item_elem, 'p')
                p_elem.text = paragraph.text.strip()
            else:
                # 处理普通段落
                p_elem = ET.SubElement(parent_elem, 'p')
                p_elem.text = paragraph.text.strip()
        
        # 处理表格
        for i, table in enumerate(doc.tables):
            table_elem = ET.SubElement(parent_elem, 'table')
            for row in table.rows:
                row_elem = ET.SubElement(table_elem, 'row')
                for cell in row.cells:
                    cell_elem = ET.SubElement(row_elem, 'cell')
                    p_elem = ET.SubElement(cell_elem, 'p')
                    p_elem.text = cell.text.strip()
    
    def _extract_metadata(self, doc: Document) -> Optional[ET.Element]:
        """提取文档元数据
        
        Args:
            doc: DOCX 文档对象
            
        Returns:
            Optional[ET.Element]: 元数据元素
        """
        metadata_elem = ET.Element('metadata')
        
        # 尝试从 DOCX 属性中提取元数据
        try:
            core_properties = doc.core_properties
            
            if core_properties.title:
                title_elem = ET.SubElement(metadata_elem, 'title')
                title_elem.text = core_properties.title
            
            if core_properties.author:
                author_elem = ET.SubElement(metadata_elem, 'author')
                author_elem.text = core_properties.author
            
            if core_properties.subject:
                subject_elem = ET.SubElement(metadata_elem, 'subject')
                subject_elem.text = core_properties.subject
            
            if core_properties.keywords:
                keywords_elem = ET.SubElement(metadata_elem, 'keywords')
                keywords_elem.text = core_properties.keywords
            
            if core_properties.created:
                created_elem = ET.SubElement(metadata_elem, 'created')
                created_elem.text = core_properties.created.strftime('%Y-%m-%d %H:%M:%S')
            
            if core_properties.modified:
                modified_elem = ET.SubElement(metadata_elem, 'modified')
                modified_elem.text = core_properties.modified.strftime('%Y-%m-%d %H:%M:%S')
            
            if core_properties.revision:
                revision_elem = ET.SubElement(metadata_elem, 'revision')
                revision_elem.text = str(core_properties.revision)
        except Exception as e:
            print(f"Warning: Failed to extract core properties: {e}")
        
        # 添加统计信息
        para_count_elem = ET.SubElement(metadata_elem, 'paragraph_count')
        para_count_elem.text = str(len(doc.paragraphs))
        
        table_count_elem = ET.SubElement(metadata_elem, 'table_count')
        table_count_elem.text = str(len(doc.tables))
        
        # 如果没有元数据，返回 None
        if len(metadata_elem) == 0:
            return None
        
        return metadata_elem
    
    def _extract_structure(self, doc: Document) -> Optional[ET.Element]:
        """提取文档结构
        
        Args:
            doc: DOCX 文档对象
            
        Returns:
            Optional[ET.Element]: 结构元素
        """
        structure_elem = ET.Element('structure')
        
        # 分析段落
        for i, paragraph in enumerate(doc.paragraphs):
            text = paragraph.text.strip()
            if not text:
                continue
            
            style_name = paragraph.style.name
            if style_name.startswith('Heading '):
                level = int(style_name.split(' ')[1])
                heading_elem = ET.SubElement(structure_elem, 'heading')
                heading_elem.set('level', str(level))
                heading_elem.set('position', str(i))
                heading_elem.text = text
            elif style_name.startswith('List '):
                list_type = "ordered" if style_name.startswith('List Number') else "unordered"
                # 避免重复添加列表标记
                if not any(
                    elem.tag == 'list' and 
                    elem.get('position') == str(i) 
                    for elem in structure_elem
                ):
                    list_elem = ET.SubElement(structure_elem, 'list')
                    list_elem.set('type', list_type)
                    list_elem.set('position', str(i))
        
        # 分析表格
        for i, table in enumerate(doc.tables):
            table_elem = ET.SubElement(structure_elem, 'table')
            table_elem.set('position', str(i))
        
        # 如果没有结构元素，返回 None
        if len(structure_elem) == 0:
            return None
        
        return structure_elem
    
    def _process_content(self, doc: Document, content_elem: ET.Element, options: Dict[str, Any]) -> None:
        """处理文档内容
        
        Args:
            doc: DOCX 文档对象
            content_elem: 内容元素
            options: 转换选项
        """
        include_formatting = options.get('include_formatting', True)
        include_images = options.get('include_images', True)
        include_headers_footers = options.get('include_headers_footers', True)
        
        # 处理页眉页脚
        if include_headers_footers:
            headers_footers_elem = self._extract_headers_footers(doc, options)
            if headers_footers_elem is not None:
                content_elem.append(headers_footers_elem)
        
        # 处理段落
        for i, paragraph in enumerate(doc.paragraphs):
            para_elem = self._process_paragraph(paragraph, i, include_formatting)
            if para_elem is not None:
                content_elem.append(para_elem)
        
        # 处理表格
        for i, table in enumerate(doc.tables):
            table_elem = self._process_table(table, i, include_formatting)
            if table_elem is not None:
                content_elem.append(table_elem)
        
        # 处理图片
        if include_images:
            images_elem = self._extract_images(doc, options)
            if images_elem is not None:
                content_elem.append(images_elem)
    
    def _process_paragraph(self, paragraph: Any, index: int, include_formatting: bool) -> Optional[ET.Element]:
        """处理段落
        
        Args:
            paragraph: 段落对象
            index: 段落索引
            include_formatting: 是否包含格式信息
            
        Returns:
            Optional[ET.Element]: 段落元素
        """
        text = paragraph.text.strip()
        if not text and not paragraph.runs:
            return None
        
        # 检测段落类型
        style_name = paragraph.style.name
        
        if style_name.startswith('Heading '):
            # 处理标题
            level = int(style_name.split(' ')[1])
            elem = ET.Element('heading')
            elem.set('id', f'heading_{index}')
            elem.set('level', str(level))
        elif style_name.startswith('List '):
            # 处理列表项
            list_type = "ordered" if style_name.startswith('List Number') else "unordered"
            elem = ET.Element('list_item')
            elem.set('id', f'list_item_{index}')
            elem.set('type', list_type)
        else:
            # 处理普通段落
            elem = ET.Element('paragraph')
            elem.set('id', f'paragraph_{index}')
        
        # 添加格式信息
        if include_formatting:
            formatting_elem = self._extract_paragraph_formatting(paragraph)
            if formatting_elem is not None:
                elem.append(formatting_elem)
        
        # 添加文本内容
        text_elem = ET.SubElement(elem, 'text')
        
        # 处理文本格式
        runs = paragraph.runs
        if runs:
            for j, run in enumerate(runs):
                run_text = run.text
                if run_text:
                    run_elem = self._process_run(run, j)
                    if run_elem is not None:
                        text_elem.append(run_elem)
        elif text:
            # 没有 runs 但有文本
            text_elem.text = text
        
        return elem
    
    def _process_run(self, run: Any, index: int) -> Optional[ET.Element]:
        """处理文本运行（包含格式的文本片段）
        
        Args:
            run: 运行对象
            index: 运行索引
            
        Returns:
            Optional[ET.Element]: 运行元素
        """
        run_text = run.text
        if not run_text:
            return None
        
        # 检查是否有格式
        has_formatting = any([
            run.bold,
            run.italic,
            run.underline,
            run.font.color,
            run.font.size,
            run.font.name
        ])
        
        if has_formatting:
            # 创建带格式的运行元素
            run_elem = ET.Element('run')
            run_elem.set('id', f'run_{index}')
            
            # 添加格式属性
            if run.bold:
                run_elem.set('bold', 'true')
            if run.italic:
                run_elem.set('italic', 'true')
            if run.underline:
                run_elem.set('underline', 'true')
            if run.font.color:
                try:
                    rgb = run.font.color.rgb
                    # 正确处理 RGBColor 对象
                    try:
                        hex_color = f'#{rgb.red:02x}{rgb.green:02x}{rgb.blue:02x}'
                    except AttributeError:
                        try:
                            hex_color = f'#{rgb.r:02x}{rgb.g:02x}{rgb.b:02x}'
                        except AttributeError:
                            hex_color = None
                    if hex_color:
                        run_elem.set('color', hex_color)
                except Exception:
                    pass
            if run.font.size:
                try:
                    size = run.font.size.pt
                    run_elem.set('font_size', str(size))
                except Exception:
                    pass
            if run.font.name:
                run_elem.set('font_name', run.font.name)
            
            run_elem.text = run_text
            return run_elem
        else:
            # 没有格式，直接返回文本
            text_elem = ET.Element('text')
            text_elem.text = run_text
            return text_elem
    
    def _process_table(self, table: Any, index: int, include_formatting: bool) -> Optional[ET.Element]:
        """处理表格
        
        Args:
            table: 表格对象
            index: 表格索引
            include_formatting: 是否包含格式信息
            
        Returns:
            Optional[ET.Element]: 表格元素
        """
        table_elem = ET.Element('table')
        table_elem.set('id', f'table_{index}')
        table_elem.set('rows', str(len(table.rows)))
        table_elem.set('columns', str(len(table.columns)))
        
        # 添加格式信息
        if include_formatting:
            formatting_elem = ET.Element('formatting')
            table_elem.append(formatting_elem)
        
        # 处理行
        rows_elem = ET.SubElement(table_elem, 'rows')
        
        for i, row in enumerate(table.rows):
            row_elem = ET.SubElement(rows_elem, 'row')
            row_elem.set('id', f'row_{index}_{i}')
            row_elem.set('cells', str(len(row.cells)))
            
            # 处理单元格
            for j, cell in enumerate(row.cells):
                cell_elem = ET.SubElement(row_elem, 'cell')
                cell_elem.set('id', f'cell_{index}_{i}_{j}')
                
                # 检查单元格合并
                try:
                    if cell.merge_cells:
                        cell_elem.set('merged', 'true')
                except AttributeError:
                    pass
                
                # 添加单元格内容
                text_elem = ET.SubElement(cell_elem, 'text')
                cell_text = ''
                for para in cell.paragraphs:
                    if para.text:
                        cell_text += para.text + '\n'
                cell_elem.set('text_length', str(len(cell_text.strip())))
                text_elem.text = cell_text.strip()
                
                # 添加单元格格式信息
                if include_formatting:
                    cell_format_elem = ET.Element('formatting')
                    cell_elem.append(cell_format_elem)
        
        return table_elem
    
    def _extract_paragraph_formatting(self, paragraph: Any) -> Optional[ET.Element]:
        """提取段落格式信息
        
        Args:
            paragraph: 段落对象
            
        Returns:
            Optional[ET.Element]: 格式信息元素
        """
        formatting_elem = ET.Element('formatting')
        
        # 提取段落样式
        style_name = paragraph.style.name
        style_elem = ET.SubElement(formatting_elem, 'style')
        style_elem.text = style_name
        
        # 提取对齐方式
        try:
            alignment = paragraph.paragraph_format.alignment
            if alignment is not None:
                # 转换为可读的对齐方式名称
                align_map = {
                    0: 'left',
                    1: 'center',
                    2: 'right',
                    3: 'justify'
                }
                align_name = align_map.get(alignment, 'unknown')
                align_elem = ET.SubElement(formatting_elem, 'alignment')
                align_elem.text = align_name
        except AttributeError:
            pass
        
        # 提取缩进信息
        try:
            if paragraph.paragraph_format.left_indent:
                left_indent = paragraph.paragraph_format.left_indent.inches
                left_indent_elem = ET.SubElement(formatting_elem, 'left_indent')
                left_indent_elem.text = str(left_indent)
            if paragraph.paragraph_format.first_line_indent:
                first_indent = paragraph.paragraph_format.first_line_indent.inches
                first_indent_elem = ET.SubElement(formatting_elem, 'first_line_indent')
                first_indent_elem.text = str(first_indent)
            if paragraph.paragraph_format.right_indent:
                right_indent = paragraph.paragraph_format.right_indent.inches
                right_indent_elem = ET.SubElement(formatting_elem, 'right_indent')
                right_indent_elem.text = str(right_indent)
        except AttributeError:
            pass
        
        # 提取间距信息
        try:
            if paragraph.paragraph_format.space_before:
                space_before = paragraph.paragraph_format.space_before.pt
                space_before_elem = ET.SubElement(formatting_elem, 'space_before')
                space_before_elem.text = str(space_before)
            if paragraph.paragraph_format.space_after:
                space_after = paragraph.paragraph_format.space_after.pt
                space_after_elem = ET.SubElement(formatting_elem, 'space_after')
                space_after_elem.text = str(space_after)
            if paragraph.paragraph_format.line_spacing:
                line_spacing = paragraph.paragraph_format.line_spacing
                line_spacing_elem = ET.SubElement(formatting_elem, 'line_spacing')
                line_spacing_elem.text = str(line_spacing)
        except AttributeError:
            pass
        
        # 提取制表符信息
        try:
            tabs = paragraph.paragraph_format.tab_stops
            if tabs:
                tabs_elem = ET.SubElement(formatting_elem, 'tab_stops')
                for tab in tabs:
                    tab_elem = ET.SubElement(tabs_elem, 'tab_stop')
                    tab_elem.set('position', str(tab.position.inches))
        except AttributeError:
            pass
        
        return formatting_elem
    
    def _extract_headers_footers(self, doc: Document, options: Dict[str, Any]) -> Optional[ET.Element]:
        """提取文档中的页眉页脚信息
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
                - include_formatting: 是否包含格式信息
                
        Returns:
            Optional[ET.Element]: 页眉页脚元素
        """
        headers_footers_elem = ET.Element('headers_footers')
        
        include_formatting = options.get('include_formatting', True)
        
        try:
            # 处理页眉
            for section in doc.sections:
                if section.header:
                    header_elem = ET.SubElement(headers_footers_elem, 'header')
                    header_elem.set('type', 'default')
                    
                    # 处理页眉内容
                    header_paras_elem = ET.SubElement(header_elem, 'paragraphs')
                    for i, para in enumerate(section.header.paragraphs):
                        para_elem = ET.SubElement(header_paras_elem, 'paragraph')
                        para_elem.set('id', f'header_para_{i}')
                        para_elem.text = para.text.strip()
            
            # 处理页脚
            for section in doc.sections:
                if section.footer:
                    footer_elem = ET.SubElement(headers_footers_elem, 'footer')
                    footer_elem.set('type', 'default')
                    
                    # 处理页脚内容
                    footer_paras_elem = ET.SubElement(footer_elem, 'paragraphs')
                    for i, para in enumerate(section.footer.paragraphs):
                        para_elem = ET.SubElement(footer_paras_elem, 'paragraph')
                        para_elem.set('id', f'footer_para_{i}')
                        para_elem.text = para.text.strip()
        except Exception as e:
            print(f"提取页眉页脚时发生错误: {e}")
            pass
        
        # 如果没有页眉页脚，返回 None
        if len(headers_footers_elem) == 0:
            return None
        
        return headers_footers_elem
    
    def _extract_images(self, doc: Document, options: Dict[str, Any]) -> Optional[ET.Element]:
        """提取 DOCX 中的图片信息
        
        Args:
            doc: DOCX 文档对象
            options: 转换选项
                - images_dir: 图片保存目录
                - include_images: 是否包含图片
                - image_prefix: 图片文件名前缀
                
        Returns:
            Optional[ET.Element]: 图片元素
        """

        images_elem = ET.Element('images')
        
        # 获取选项
        images_dir = options.get('images_dir', 'images')
        image_prefix = options.get('image_prefix', 'image_')
        
        # 确保图片目录存在
        os.makedirs(images_dir, exist_ok=True)
        
        # 提取文档中的图片
        image_count = 0
        for rel in doc.part.rels.values():
            if "image" in rel.target_ref:
                try:
                    # 获取图片内容
                    image_part = rel.target_part
                    image_content = image_part.blob
                    
                    # 确定图片扩展名
                    content_type = image_part.content_type
                    ext_map = {
                        'image/jpeg': '.jpg',
                        'image/png': '.png',
                        'image/gif': '.gif',
                        'image/bmp': '.bmp',
                        'image/tiff': '.tif',
                        'image/webp': '.webp',
                        'image/svg+xml': '.svg'
                    }
                    ext = ext_map.get(content_type, '.bin')
                    
                    # 保存图片
                    image_name = f'{image_prefix}{image_count + 1}{ext}'
                    image_path = os.path.join(images_dir, image_name)
                    with open(image_path, 'wb') as f:
                        f.write(image_content)
                    
                    # 创建图片元素
                    image_elem = ET.SubElement(images_elem, 'image')
                    image_elem.set('id', f'img_{image_count + 1}')
                    image_elem.set('name', image_name)
                    image_elem.set('path', image_path)
                    image_elem.set('content_type', content_type)
                    
                    # 添加图片元数据
                    size_elem = ET.SubElement(image_elem, 'size')
                    size_elem.text = str(len(image_content))
                    
                    # 尝试获取图片尺寸
                    try:
                        import io
                        from PIL import Image
                        img = Image.open(io.BytesIO(image_content))
                        width, height = img.size
                        dimensions_elem = ET.SubElement(image_elem, 'dimensions')
                        dimensions_elem.set('width', str(width))
                        dimensions_elem.set('height', str(height))
                        dimensions_elem.text = f'{width}x{height}'
                    except ImportError:
                        # PIL 未安装，跳过尺寸获取
                        pass
                    except Exception as e:
                        # 其他错误，跳过尺寸获取
                        print(f"Warning: Failed to get image dimensions: {e}")
                    
                    image_count += 1
                except Exception as e:
                    print(f"Warning: Failed to extract image: {e}")
                    continue
        
        # 如果没有图片，返回 None
        if image_count == 0:
            return None
        
        return images_elem
    
    def get_supported_formats(self) -> tuple:
        """获取支持的格式"""
        return ('docx', 'xml')
