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

from typing import Any, Optional, Dict, List
from hos_m2f.converters.base_converter import BaseConverter
from docx import Document
from docx.shared import RGBColor
import xml.etree.ElementTree as ET
import io


class XMLToDOCXConverter(BaseConverter):
    """XML到DOCX格式转换器"""
    
    def convert(self, input_content: bytes, options: Optional[Dict[str, Any]] = None) -> bytes:
        """将XML转换为DOCX
        
        Args:
            input_content: XML文件的二进制数据
            options: 转换选项
                - include_formatting: 是否包含格式信息
                - include_structure: 是否包含文档结构
                
        Returns:
            bytes: DOCX文件的二进制数据
        """
        if options is None:
            options = {}
        
        # 解析XML
        xml_root = ET.fromstring(input_content)
        
        # 创建DOCX文档
        doc = Document()
        
        # 转换XML到DOCX
        self._xml_to_docx(xml_root, doc, options)
        
        # 保存为字节流
        output_stream = io.BytesIO()
        doc.save(output_stream)
        output_stream.seek(0)
        
        return output_stream.read()
    
    def _xml_to_docx(self, xml_root: ET.Element, doc: Document, options: Dict[str, Any]) -> None:
        """将XML元素转换为DOCX文档
        
        Args:
            xml_root: XML根元素
            doc: DOCX文档对象
            options: 转换选项
        """
        include_formatting = options.get('include_formatting', True)
        
        # 处理content元素
        content_elem = xml_root.find('content')
        if content_elem:
            for elem in content_elem:
                if elem.tag == 'heading':
                    self._process_heading(elem, doc, include_formatting)
                elif elem.tag == 'paragraph':
                    self._process_paragraph(elem, doc, include_formatting)
                elif elem.tag == 'list_item':
                    self._process_list_item(elem, doc, include_formatting)
                elif elem.tag == 'table':
                    self._process_table(elem, doc, include_formatting)
    
    def _process_heading(self, elem: ET.Element, doc: Document, include_formatting: bool) -> None:
        """处理标题元素
        
        Args:
            elem: XML元素
            doc: DOCX文档对象
            include_formatting: 是否包含格式信息
        """
        level = int(elem.get('level', '1'))
        text_elem = elem.find('text')
        text = text_elem.text.strip() if text_elem is not None and text_elem.text else ''
        
        # 添加标题
        heading = doc.add_heading(text, level=level)
        
        # 处理格式信息
        if include_formatting:
            format_elem = elem.find('formatting')
            if format_elem:
                self._apply_formatting(heading, format_elem)
    
    def _process_paragraph(self, elem: ET.Element, doc: Document, include_formatting: bool) -> None:
        """处理段落元素
        
        Args:
            elem: XML元素
            doc: DOCX文档对象
            include_formatting: 是否包含格式信息
        """
        text_elem = elem.find('text')
        text = text_elem.text.strip() if text_elem is not None and text_elem.text else ''
        
        # 添加段落
        paragraph = doc.add_paragraph()
        
        # 处理文本内容和格式
        if text:
            self._process_run_content(paragraph, text_elem)
        
        # 处理段落格式信息
        if include_formatting:
            format_elem = elem.find('formatting')
            if format_elem:
                self._apply_formatting(paragraph, format_elem)
    
    def _process_list_item(self, elem: ET.Element, doc: Document, include_formatting: bool) -> None:
        """处理列表项元素
        
        Args:
            elem: XML元素
            doc: DOCX文档对象
            include_formatting: 是否包含格式信息
        """
        list_type = elem.get('type', 'unordered')
        text_elem = elem.find('text')
        text = text_elem.text.strip() if text_elem is not None and text_elem.text else ''
        
        # 添加列表项
        style = 'List Number' if list_type == 'ordered' else 'List Bullet'
        paragraph = doc.add_paragraph(text, style=style)
        
        # 处理格式信息
        if include_formatting:
            format_elem = elem.find('formatting')
            if format_elem:
                self._apply_formatting(paragraph, format_elem)
    
    def _process_table(self, elem: ET.Element, doc: Document, include_formatting: bool) -> None:
        """处理表格元素
        
        Args:
            elem: XML元素
            doc: DOCX文档对象
            include_formatting: 是否包含格式信息
        """
        rows_elem = elem.find('rows')
        if not rows_elem:
            return
        
        # 获取行数和列数
        row_elements = rows_elem.findall('row')
        if not row_elements:
            return
        
        # 获取第一行的单元格数作为列数
        first_row_cells = row_elements[0].findall('cell')
        cols = len(first_row_cells)
        rows = len(row_elements)
        
        # 创建表格
        table = doc.add_table(rows=rows, cols=cols)
        
        # 填充表格内容
        for i, row_elem in enumerate(row_elements):
            cell_elements = row_elem.findall('cell')
            for j, cell_elem in enumerate(cell_elements):
                if j < cols:
                    text_elem = cell_elem.find('text')
                    text = text_elem.text.strip() if text_elem is not None and text_elem.text else ''
                    table.cell(i, j).text = text
    
    def _process_run_content(self, paragraph: Any, text_elem: ET.Element) -> None:
        """处理文本运行内容
        
        Args:
            paragraph: 段落对象
            text_elem: 文本元素
        """
        # 处理文本和格式
        # 检查是否有run子元素
        run_elements = text_elem.findall('.//run')
        if run_elements:
            for run_elem in run_elements:
                run_text = run_elem.text.strip() if run_elem.text else ''
                if run_text:
                    run = paragraph.add_run(run_text)
                    # 应用run格式
                    self._apply_run_formatting(run, run_elem)
        else:
            # 没有run元素，直接添加文本
            paragraph.add_run(text_elem.text.strip())
    
    def _apply_formatting(self, paragraph: Any, format_elem: ET.Element) -> None:
        """应用段落格式
        
        Args:
            paragraph: 段落对象
            format_elem: 格式元素
        """
        # 处理段落样式
        style_elem = format_elem.find('style')
        if style_elem is not None and style_elem.text:
            # 尝试应用样式
            try:
                paragraph.style = style_elem.text
            except Exception:
                pass
        
        # 处理对齐方式
        alignment_elem = format_elem.find('alignment')
        if alignment_elem is not None and alignment_elem.text:
            align_map = {
                'left': 0,
                'center': 1,
                'right': 2,
                'justify': 3
            }
            align_value = align_map.get(alignment_elem.text, 0)
            paragraph.paragraph_format.alignment = align_value
        
        # 处理缩进
        left_indent_elem = format_elem.find('left_indent')
        if left_indent_elem is not None and left_indent_elem.text:
            try:
                left_indent = float(left_indent_elem.text)
                from docx.shared import Inches
                paragraph.paragraph_format.left_indent = Inches(left_indent)
            except Exception:
                pass
        
        first_indent_elem = format_elem.find('first_line_indent')
        if first_indent_elem is not None and first_indent_elem.text:
            try:
                first_indent = float(first_indent_elem.text)
                from docx.shared import Inches
                paragraph.paragraph_format.first_line_indent = Inches(first_indent)
            except Exception:
                pass
    
    def _apply_run_formatting(self, run: Any, run_elem: ET.Element) -> None:
        """应用运行格式
        
        Args:
            run: 运行对象
            run_elem: 运行元素
        """
        # 应用粗体
        if run_elem.get('bold') == 'true':
            run.bold = True
        
        # 应用斜体
        if run_elem.get('italic') == 'true':
            run.italic = True
        
        # 应用下划线
        if run_elem.get('underline') == 'true':
            run.underline = True
        
        # 应用颜色
        color = run_elem.get('color')
        if color:
            try:
                # 移除#前缀
                if color.startswith('#'):
                    color = color[1:]
                # 解析RGB颜色
                if len(color) == 6:
                    red = int(color[0:2], 16)
                    green = int(color[2:4], 16)
                    blue = int(color[4:6], 16)
                    run.font.color.rgb = RGBColor(red, green, blue)
            except Exception:
                pass
        
        # 应用字体大小
        font_size = run_elem.get('font_size')
        if font_size:
            try:
                size = float(font_size)
                from docx.shared import Pt
                run.font.size = Pt(size)
            except Exception:
                pass
        
        # 应用字体名称
        font_name = run_elem.get('font_name')
        if font_name:
            run.font.name = font_name
    
    def get_supported_formats(self) -> tuple:
        """获取支持的格式"""
        return ('xml', 'docx')
