"""DOCX到XML格式转换器"""

from typing import Any, Optional, Dict, List, Tuple
from hos_m2f.converters.base_converter import BaseConverter
from docx import Document
import os
import io


class DOCXToXMLConverter(BaseConverter):
    """DOCX到XML格式转换器"""
    
    def convert(self, input_content: bytes, options: Optional[Dict[str, Any]] = None) -> bytes:
        """将DOCX转换为XML
        
        Args:
            input_content: DOCX文件的二进制数据
            options: 转换选项
                - include_images: 是否包含图片
                - include_formatting: 是否包含格式信息
                - include_structure: 是否包含文档结构
                
        Returns:
            bytes: XML文件的二进制数据
        """
        if options is None:
            options = {}
        
        # 加载DOCX文档
        doc = Document(io.BytesIO(input_content))
        
        # 转换为XML
        xml_content = self._docx_to_xml(doc, options)
        
        # 生成完整的XML文档
        full_xml = f'''<?xml version="1.0" encoding="UTF-8"?>
<document>
{xml_content}
</document>'''
        
        return full_xml.encode('utf-8')
    
    def _docx_to_xml(self, doc: Document, options: Dict[str, Any]) -> str:
        """将DOCX文档转换为XML结构
        
        Args:
            doc: DOCX文档对象
            options: 转换选项
            
        Returns:
            str: XML结构字符串
        """
        xml_parts = []
        
        # 提取元数据
        include_formatting = options.get('include_formatting', True)
        include_structure = options.get('include_structure', True)
        include_images = options.get('include_images', True)
        
        # 添加元数据
        metadata = self._extract_metadata(doc)
        if metadata:
            xml_parts.append('<metadata>')
            for key, value in metadata.items():
                xml_parts.append(f'<{key}>{self._escape_xml(str(value))}</{key}>')
            xml_parts.append('</metadata>')
        
        # 添加文档结构
        if include_structure:
            structure = self._extract_structure(doc)
            if structure:
                xml_parts.append('<structure>')
                for item in structure:
                    xml_parts.append(self._structure_item_to_xml(item))
                xml_parts.append('</structure>')
        
        # 添加内容
        xml_parts.append('<content>')
        
        # 处理段落
        for i, paragraph in enumerate(doc.paragraphs):
            paragraph_xml = self._paragraph_to_xml(paragraph, i, include_formatting)
            if paragraph_xml:
                xml_parts.append(paragraph_xml)
        
        # 处理表格
        for i, table in enumerate(doc.tables):
            table_xml = self._table_to_xml(table, i, include_formatting)
            if table_xml:
                xml_parts.append(table_xml)
        
        # 处理图片
        if include_images:
            images = self._extract_images(doc)
            if images:
                xml_parts.append('<images>')
                for j, image in enumerate(images):
                    xml_parts.append(f'<image id="img_{j+1}" name="{self._escape_xml(image["name"])}" content_type="{self._escape_xml(image["content_type"])}" />')
                xml_parts.append('</images>')
        
        xml_parts.append('</content>')
        
        return '\n'.join(xml_parts)
    
    def _extract_metadata(self, doc: Document) -> Dict[str, Any]:
        """提取文档元数据
        
        Args:
            doc: DOCX文档对象
            
        Returns:
            Dict[str, Any]: 元数据字典
        """
        metadata = {}
        
        # 尝试从DOCX属性中提取元数据
        try:
            core_properties = doc.core_properties
            if core_properties.title:
                metadata["title"] = core_properties.title
            if core_properties.author:
                metadata["author"] = core_properties.author
            if core_properties.subject:
                metadata["subject"] = core_properties.subject
            if core_properties.keywords:
                metadata["keywords"] = core_properties.keywords
            if core_properties.created:
                metadata["created"] = core_properties.created.strftime('%Y-%m-%d %H:%M:%S')
            if core_properties.modified:
                metadata["modified"] = core_properties.modified.strftime('%Y-%m-%d %H:%M:%S')
            if core_properties.revision:
                metadata["revision"] = str(core_properties.revision)
        except Exception as e:
            print(f"Warning: Failed to extract core properties: {e}")
        
        # 统计文档信息
        metadata["paragraph_count"] = len(doc.paragraphs)
        metadata["table_count"] = len(doc.tables)
        
        return metadata
    
    def _extract_structure(self, doc: Document) -> List[Dict[str, Any]]:
        """提取文档结构
        
        Args:
            doc: DOCX文档对象
            
        Returns:
            List[Dict[str, Any]]: 结构项列表
        """
        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])
                structure.append({
                    "type": "heading",
                    "level": level,
                    "title": text,
                    "position": i
                })
            elif paragraph.style.name.startswith('List '):
                list_type = "ordered" if paragraph.style.name.startswith('List Number') else "unordered"
                if not any(item.get('type') == 'list' and item.get('position') == i for item in structure):
                    structure.append({
                        "type": "list",
                        "list_type": list_type,
                        "position": i
                    })
        
        # 分析表格
        for i, table in enumerate(doc.tables):
            structure.append({
                "type": "table",
                "position": i
            })
        
        return structure
    
    def _structure_item_to_xml(self, item: Dict[str, Any]) -> str:
        """将结构项转换为XML
        
        Args:
            item: 结构项字典
            
        Returns:
            str: XML字符串
        """
        if item['type'] == 'heading':
            return f'<heading level="{item["level"]}" position="{item["position"]}">{self._escape_xml(item["title"])}</heading>'
        elif item['type'] == 'list':
            return f'<list type="{item["list_type"]}" position="{item["position"]}" />'
        elif item['type'] == 'table':
            return f'<table position="{item["position"]}" />'
        return ''
    
    def _paragraph_to_xml(self, paragraph: Any, index: int, include_formatting: bool) -> str:
        """将段落转换为XML
        
        Args:
            paragraph: 段落对象
            index: 段落索引
            include_formatting: 是否包含格式信息
            
        Returns:
            str: XML字符串
        """
        text = paragraph.text.strip()
        if not text:
            return ''
        
        # 检测段落类型
        style_name = paragraph.style.name
        para_type = "paragraph"
        if style_name.startswith('Heading '):
            para_type = "heading"
            level = int(style_name.split(' ')[1])
        elif style_name.startswith('List '):
            para_type = "list_item"
            list_type = "ordered" if style_name.startswith('List Number') else "unordered"
        
        # 开始构建XML
        xml_parts = []
        
        # 段落标签
        if para_type == "heading":
            xml_parts.append(f'<heading id="heading_{index}" level="{level}">')
        elif para_type == "list_item":
            xml_parts.append(f'<list_item id="list_item_{index}" type="{list_type}">')
        else:
            xml_parts.append(f'<paragraph id="paragraph_{index}">')
        
        # 添加格式信息
        if include_formatting:
            format_xml = self._extract_formatting(paragraph)
            if format_xml:
                xml_parts.append('<formatting>')
                xml_parts.append(format_xml)
                xml_parts.append('</formatting>')
        
        # 添加文本内容
        if include_formatting:
            # 详细的文本格式处理
            runs_xml = self._process_runs(paragraph.runs)
            xml_parts.append('<text>')
            xml_parts.append(runs_xml)
            xml_parts.append('</text>')
        else:
            # 简单的文本处理
            xml_parts.append(f'<text>{self._escape_xml(text)}</text>')
        
        # 结束标签
        if para_type == "heading":
            xml_parts.append('</heading>')
        elif para_type == "list_item":
            xml_parts.append('</list_item>')
        else:
            xml_parts.append('</paragraph>')
        
        return '\n'.join(xml_parts)
    
    def _table_to_xml(self, table: Any, index: int, include_formatting: bool) -> str:
        """将表格转换为XML
        
        Args:
            table: 表格对象
            index: 表格索引
            include_formatting: 是否包含格式信息
            
        Returns:
            str: XML字符串
        """
        xml_parts = []
        xml_parts.append(f'<table id="table_{index}">')
        
        # 添加格式信息
        if include_formatting:
            # 提取表格格式信息
            xml_parts.append('<formatting>')
            # 这里可以添加表格级别的格式信息
            xml_parts.append('</formatting>')
        
        # 处理行
        xml_parts.append('<rows>')
        for i, row in enumerate(table.rows):
            xml_parts.append(f'<row id="row_{index}_{i}">')
            
            # 处理单元格
            for j, cell in enumerate(row.cells):
                xml_parts.append(f'<cell id="cell_{index}_{i}_{j}">')
                
                # 处理单元格内容
                cell_text = cell.text.strip()
                if cell_text:
                    xml_parts.append(f'<text>{self._escape_xml(cell_text)}</text>')
                
                # 处理单元格格式
                if include_formatting:
                    # 提取单元格格式信息
                    xml_parts.append('<formatting>')
                    # 这里可以添加单元格级别的格式信息
                    xml_parts.append('</formatting>')
                
                xml_parts.append('</cell>')
            
            xml_parts.append('</row>')
        xml_parts.append('</rows>')
        
        xml_parts.append('</table>')
        
        return '\n'.join(xml_parts)
    
    def _extract_images(self, doc: Document) -> List[Dict[str, Any]]:
        """提取DOCX中的图片
        
        Args:
            doc: DOCX文档对象
            
        Returns:
            List[Dict[str, Any]]: 提取的图片信息
        """
        images = []
        
        # 提取文档中的图片
        for i, rel in enumerate(doc.part.rels.values()):
            if "image" in rel.target_ref:
                # 获取图片内容
                image_part = rel.target_part
                image_content = image_part.blob
                
                # 确定图片扩展名
                content_type = image_part.content_type
                if content_type == 'image/jpeg':
                    ext = '.jpg'
                elif content_type == 'image/png':
                    ext = '.png'
                elif content_type == 'image/gif':
                    ext = '.gif'
                else:
                    ext = '.bin'
                
                # 记录图片信息
                images.append({
                    'name': f'image_{i+1}{ext}',
                    'content_type': content_type,
                    'content': image_content
                })
        
        return images
    
    def _extract_formatting(self, paragraph: Any) -> str:
        """提取段落格式信息
        
        Args:
            paragraph: 段落对象
            
        Returns:
            str: 格式信息XML
        """
        format_parts = []
        
        # 提取段落样式
        style_name = paragraph.style.name
        format_parts.append(f'<style>{self._escape_xml(style_name)}</style>')
        
        # 提取对齐方式
        try:
            alignment = paragraph.paragraph_format.alignment
            if alignment:
                # 转换为可读的对齐方式名称
                align_map = {
                    0: 'left',
                    1: 'center',
                    2: 'right',
                    3: 'justify'
                }
                align_name = align_map.get(alignment, 'unknown')
                format_parts.append(f'<alignment>{align_name}</alignment>')
        except AttributeError:
            pass
        
        # 提取缩进信息
        try:
            if paragraph.paragraph_format.left_indent:
                left_indent = paragraph.paragraph_format.left_indent.inches
                format_parts.append(f'<left_indent>{left_indent}</left_indent>')
            if paragraph.paragraph_format.first_line_indent:
                first_indent = paragraph.paragraph_format.first_line_indent.inches
                format_parts.append(f'<first_line_indent>{first_indent}</first_line_indent>')
        except AttributeError:
            pass
        
        return '\n'.join(format_parts)
    
    def _process_runs(self, runs: List[Any]) -> str:
        """处理文本运行（包含格式的文本片段）
        
        Args:
            runs: 运行对象列表
            
        Returns:
            str: XML字符串
        """
        run_parts = []
        
        for i, run in enumerate(runs):
            run_text = run.text
            if not run_text:
                continue
            
            # 检查格式
            has_formatting = any([
                run.bold,
                run.italic,
                run.underline,
                run.font.color,
                run.font.size,
                run.font.name
            ])
            
            if has_formatting:
                # 开始格式标签
                format_attrs = []
                if run.bold:
                    format_attrs.append('bold="true"')
                if run.italic:
                    format_attrs.append('italic="true"')
                if run.underline:
                    format_attrs.append('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:
                            format_attrs.append(f'color="{hex_color}"')
                    except Exception:
                        pass
                if run.font.size:
                    try:
                        size = run.font.size.pt
                        format_attrs.append(f'font_size="{size}"')
                    except Exception:
                        pass
                if run.font.name:
                    format_attrs.append(f'font_name="{self._escape_xml(run.font.name)}"')
                
                # 构建格式标签
                if format_attrs:
                    attrs_str = ' ' + ' '.join(format_attrs)
                    run_parts.append(f'<run{attrs_str}>{self._escape_xml(run_text)}</run>')
                else:
                    run_parts.append(self._escape_xml(run_text))
            else:
                run_parts.append(self._escape_xml(run_text))
        
        return ''.join(run_parts)
    
    def _escape_xml(self, text: str) -> str:
        """转义XML特殊字符
        
        Args:
            text: 原始文本
            
        Returns:
            str: 转义后的文本
        """
        escape_map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&apos;'
        }
        
        for char, replacement in escape_map.items():
            text = text.replace(char, replacement)
        
        return text
    
    def get_supported_formats(self) -> tuple:
        """获取支持的格式"""
        return ('docx', 'xml')
