"""
skills/docx_skill.py - DOCX Word 文档生成/编辑技能
===============================================
基于 python-docx 生成和编辑 Word 文档，融入 MiniMax DOCX Skill 设计理念。
支持标题、段落、列表、表格、图片、页眉页脚、样式等。
"""
from __future__ import annotations

import json
import os
import time
from pathlib import Path
from typing import Any, Dict, List, Optional

from aiskills.base import Skill, SkillParameter, SkillResult


class DOCXCreateSkill(Skill):
    """生成 Word 文档"""
    name = "docx_create"
    description = (
        "生成 Word (DOCX) 文档。支持多级标题、段落、列表、表格、图片等。"
        "content 为 JSON 数组，每项: {type, text/items/headers/rows/path...}。"
        "type 可选: h1/h2/h3/body/bullet/numbered/table/image/pagebreak/spacer。"
    )
    category = "doc"
    dangerous = True
    parameters = [
        SkillParameter("content", "string",
            "内容块 JSON 数组。示例: [{\"type\":\"h1\",\"text\":\"报告\"},{\"type\":\"body\",\"text\":\"正文\"}]",
            required=True),
        SkillParameter("output_path", "string", "输出 DOCX 文件路径", required=True),
        SkillParameter("title", "string", "文档标题", required=False, default=""),
        SkillParameter("author", "string", "作者", required=False, default=""),
        SkillParameter("font", "string", "中文字体", required=False, default="SimHei"),
    ]

    async def execute(self, content: str = "", output_path: str = "",
                      title: str = "", author: str = "",
                      font: str = "SimHei", **kwargs) -> SkillResult:
        try:
            from docx import Document
            from docx.shared import Inches, Cm, Pt, Emu, RGBColor
            from docx.enum.text import WD_ALIGN_PARAGRAPH
            from docx.enum.table import WD_TABLE_ALIGNMENT
        except ImportError:
            return SkillResult(success=False, error="python-docx 未安装: pip install python-docx")

        try:
            if isinstance(content, str):
                content = content.strip()
                try:
                    blocks = json.loads(content)
                except json.JSONDecodeError:
                    decoder = json.JSONDecoder()
                    blocks, _ = decoder.raw_decode(content)
            else:
                blocks = content
            if not isinstance(blocks, list):
                blocks = [{"type": "body", "text": str(blocks)}]
        except (json.JSONDecodeError, ValueError) as e:
            return SkillResult(success=False, error=f"content JSON 解析失败: {e}")

        try:
            if not output_path.strip():
                default_dir = Path.home() / ".myagent" / "data" / "workspace" / "userfiles"
                default_dir.mkdir(parents=True, exist_ok=True)
                out = default_dir / f"doc_{int(time.time())}.docx"
            else:
                out = Path(output_path).expanduser().resolve()
            out.parent.mkdir(parents=True, exist_ok=True)

            doc = Document()
            if title:
                doc.core_properties.title = title
            if author:
                doc.core_properties.author = author

            style = doc.styles["Normal"]
            rpr = style.font
            rpr.name = font
            rpr.size = Pt(11)

            for level, size in [("Heading 1", 22), ("Heading 2", 16), ("Heading 3", 13)]:
                if level in doc.styles:
                    hs = doc.styles[level]
                    hs.font.name = font
                    hs.font.size = Pt(size)
                    hs.font.color.rgb = RGBColor(0x1a, 0x36, 0x5d)

            for block in blocks:
                if not isinstance(block, dict):
                    continue
                bt = block.get("type", "body")

                if bt in ("h1", "h2", "h3"):
                    heading_map = {"h1": 0, "h2": 1, "h3": 2}
                    doc.add_heading(block.get("text", ""), level=heading_map[bt] + 1)
                elif bt == "body":
                    p = doc.add_paragraph(block.get("text", ""))
                    p.paragraph_format.first_line_indent = Cm(0.74)
                    p.paragraph_format.line_spacing = 1.5
                elif bt == "bullet":
                    for item in block.get("items", []):
                        doc.add_paragraph(item, style="List Bullet")
                elif bt == "numbered":
                    for item in block.get("items", []):
                        doc.add_paragraph(item, style="List Number")
                elif bt == "table":
                    headers = block.get("headers", [])
                    rows = block.get("rows", [])
                    if headers:
                        table = doc.add_table(rows=1 + len(rows), cols=len(headers))
                        table.style = "Light Grid Accent 1"
                        table.alignment = WD_TABLE_ALIGNMENT.CENTER
                        for j, h in enumerate(headers):
                            cell = table.rows[0].cells[j]
                            cell.text = str(h)
                            for run in cell.paragraphs[0].runs:
                                run.bold = True
                        for i, row in enumerate(rows):
                            for j, val in enumerate(row):
                                if j < len(table.columns):
                                    table.rows[i + 1].cells[j].text = str(val)
                elif bt == "image":
                    img_path = block.get("path", "")
                    img_w = block.get("width", 0)
                    if img_path and os.path.isfile(img_path):
                        try:
                            if img_w > 0:
                                doc.add_picture(img_path, width=Emu(int(img_w)))
                            else:
                                doc.add_picture(img_path, width=Inches(5.5))
                        except Exception as e:
                            doc.add_paragraph(f"[图片加载失败: {e}]")
                elif bt == "pagebreak":
                    doc.add_page_break()
                elif bt == "spacer":
                    doc.add_paragraph("")

            doc.save(str(out))
            return SkillResult(
                success=True,
                message=f"Word 文档已生成: {out}",
                files=[str(out)],
                data={"path": str(out), "blocks": len(blocks)},
            )
        except Exception as e:
            return SkillResult(success=False, error=f"DOCX 生成失败: {e}")


class DOCXReadSkill(Skill):
    """读取 Word 文档内容"""
    name = "docx_read"
    description = "读取 Word (DOCX) 文件，提取文本内容。支持提取表格数据。"
    category = "doc"
    parameters = [
        SkillParameter("path", "string", "DOCX 文件路径", required=True),
        SkillParameter("max_chars", "integer", "最大字符数", required=False, default=50000),
    ]

    async def execute(self, path: str = "", max_chars: int = 50000, **kwargs) -> SkillResult:
        try:
            from docx import Document
        except ImportError:
            return SkillResult(success=False, error="python-docx 未安装: pip install python-docx")

        fp = Path(path).expanduser().resolve()
        if not fp.exists():
            return SkillResult(success=False, error=f"文件不存在: {path}")

        try:
            doc = Document(str(fp))
            parts = []
            for para in doc.paragraphs:
                style_name = para.style.name if para.style else ""
                prefix = ""
                if "Heading" in style_name:
                    level = style_name.replace("Heading", "").strip()
                    prefix = f"[{'#' * int(level) if level.isdigit() else '#'}] "
                elif "Bullet" in style_name:
                    prefix = "  * "
                elif "Number" in style_name or "List" in style_name:
                    prefix = "  - "
                text = para.text.strip()
                if text:
                    parts.append(f"{prefix}{text}")

            for i, table in enumerate(doc.tables):
                rows = []
                for row in table.rows:
                    cells = [cell.text.strip() for cell in row.cells]
                    rows.append(" | ".join(cells))
                if rows:
                    parts.append(f"\n[表格 {i+1}]")
                    parts.append(rows[0])
                    if len(rows) > 1:
                        parts.append("-" * len(rows[0]))
                        parts.extend(rows[1:])

            full = "\n".join(parts)
            if len(full) > max_chars:
                full = full[:max_chars] + f"\n\n... (截断，共 {len(full)} 字符)"

            return SkillResult(
                success=True,
                message=f"已读取 Word 文档: {fp.name}",
                data={"path": str(fp), "paragraphs": len(doc.paragraphs),
                      "tables": len(doc.tables)},
                output=full,
            )
        except Exception as e:
            return SkillResult(success=False, error=f"DOCX 读取失败: {e}")
