from __future__ import annotations

"""
Same-as 规则工具：
- 当某个 section 的脚注包含 "Same as Table X.Y"（或 Listing），表示该 section 内容与目标表格一致。
- 需要复制目标表格的拆分文件，替换标题为当前 section 的标题，并将文件名改为当前 section 的 label。

使用前提：
- 已调用 split_docx_into_tables_with_copy 生成了各表格的拆分文件，并写回了 TableItem.local_path。

核心入口：
- apply_same_as_rule(docx_content: List[TableItem]) -> List[TableItem]
  遍历 docx_content，将含有 Same-as 的且无表格的 section，复制目标拆分文件并更新 local_path。
"""

import os
import re
from pathlib import Path
from typing import List, Optional, Tuple
from docx import Document
from docx.oxml.text.paragraph import CT_P
from docx.oxml.table import CT_Tbl
from docx.text.paragraph import Paragraph

from ..models import TableItem
from ..word.docx_file_parse_util import extract_title_label
from ..utils.text_utils import slugify_text


def _slugify(text: str) -> str:
    """与拆分工具保持一致：空白转下划线，移除非字母数字/点/横线字符，并折叠连续下划线。"""
    return slugify_text(text)


def _unique_local_path(base_stem: str, label: str, output_dir: str, used_paths: set) -> str:
    """生成唯一输出路径，与拆分逻辑保持一致。"""
    safe_label = _slugify(label)
    fname = f"{base_stem}.{safe_label}.docx"
    path = os.path.join(output_dir, fname)
    counter = 2
    while path in used_paths or os.path.exists(path):
        fname = f"{base_stem}#{safe_label}_{counter}.docx"
        path = os.path.join(output_dir, fname)
        counter += 1
    used_paths.add(path)
    return path


def _normalize_label(label: Optional[str]) -> Optional[str]:
    """统一标签大小写与空白：'table 1.2' -> 'Table 1.2'。"""
    if not label:
        return None
    s = re.sub(r"\s+", " ", label.strip())
    s = re.sub(r"^(table|listing)", lambda m: m.group(1).capitalize(), s, flags=re.I)
    return s


def _extract_same_as_target_label(text: Optional[str]) -> Optional[str]:
    """
    从脚注文本中提取 "Same as <Prefix> <Number>" 的目标标签。
    例如："Same as Table 1.1" -> "Table 1.1"；大小写不敏感。
    """
    if not text:
        return None
    m = re.search(r"(?i)\bSame\s+as\s+(Table|Listing)\s+([0-9]+(?:\.[0-9]+)*)", text)
    if not m:
        return None
    prefix = m.group(1).capitalize()
    number = m.group(2)
    return f"{prefix} {number}"


def _get_base_stem_and_output_dir(ref_path: str) -> Tuple[str, str]:
    """根据已存在的拆分文件推导 base_stem 与输出目录。"""
    p = Path(ref_path)
    name = p.name  # 形如: <base_stem>.<safe_label>.docx 或 <base_stem>#<safe_label>_N.docx
    base_stem = name.split(".")[0]
    return base_stem, str(p.parent)


def _replace_leading_title(doc: Document, new_title: str):
    """
    将文档中表格之前的所有标题段落替换为 new_title。
    - 若存在多个标题段落，仅第一个替换为新标题，其余清空文本。
    - 不改变段落样式，仅替换文本内容。
    """
    body = doc._element.body
    first = True
    for child in body.iterchildren():
        if isinstance(child, CT_Tbl):
            break
        if isinstance(child, CT_P):
            para = Paragraph(child, doc)
            if first:
                para.text = (new_title or "").strip()
                first = False
            else:
                # 避免多余旧标题残留
                para.text = ""


def apply_same_as_rule(docx_content: List[TableItem]) -> List[TableItem]:
    """
    应用 "Same as Table/Listing" 规则：
    - 对于无表格的 section，若脚注包含 "Same as Table X.Y"，则复制目标表格的拆分文件，
      将标题替换为当前 section 标题，并按当前 label 命名新文件，更新 current.local_path。

    参数:
    - docx_content: 解析并拆分后的 TableItem 列表；其中有表格的项应已写入 local_path。

    返回: 更新后的 docx_content。
    """
    # 建立 label -> 拆分文件路径 的映射（仅限已生成文件的表格项）
    label_to_path: dict[str, str] = {}
    used_paths: set = set()
    for sec in docx_content:
        if sec.local_path:
            used_paths.add(sec.local_path)
        if sec.table_index is not None and sec.label and sec.local_path:
            norm = _normalize_label(sec.label)
            if norm:
                label_to_path[norm] = sec.local_path

    # 遍历需要应用 same-as 的 section
    for sec in docx_content:
        # 必须是无表格的 section，且包含 same-as 脚注
        if sec.table_index is not None:
            continue
        target_label = _extract_same_as_target_label(sec.footnote)
        if not target_label:
            continue
        target_label = _normalize_label(target_label)
        if target_label is None:
            continue
        ref_path = label_to_path.get(target_label)
        if not ref_path or not os.path.exists(ref_path):
            # 无法匹配到目标拆分文件，跳过
            continue

        # 复制并替换标题
        ref_doc = Document(ref_path)
        # 新标题：优先使用当前 section.title；其次尝试由标题提取 label；再退化为 target_label
        new_title = (sec.title or "").strip()
        if not new_title:
            # 尝试从标题中提取简洁标签
            inferred = extract_title_label(sec.title or "")
            new_title = inferred or target_label or ""
        _replace_leading_title(ref_doc, new_title)

        # 新文件名标签：优先当前 sec.label；其次从标题提取；再退化 target_label
        new_label = _normalize_label(sec.label) or extract_title_label(sec.title or "") or target_label or "Table"

        base_stem, output_dir = _get_base_stem_and_output_dir(ref_path)
        new_path = _unique_local_path(base_stem, new_label, output_dir, used_paths)
        ref_doc.save(new_path)

        # 写回当前 section 的输出路径
        sec.local_path = new_path
        # 可选：打印以便调试
        print(f"Same-as applied: '{new_label}' -> {new_path} (from {target_label})")

    return docx_content


# if __name__ == "__main__":
#     # 仅作开发时的快速说明：
#     # 在外部流程中应：
#     # 1) 先 extract_docx_content_with_metadata
#     # 2) 再 split_docx_into_tables_with_copy（生成 local_path）
#     # 3) 然后调用 apply_same_as_rule(docx_content)
#     print("rule_same_as_util is a library module; import and call apply_same_as_rule.")