from __future__ import annotations

import re
from dataclasses import asdict
from pathlib import Path
from typing import List, Dict, Optional

from ..framework.command import Command
from ..framework.context import Context
from ..framework.command_registry import CommandRegistry

from ..common.models import TableItem
from ..common.utils.title_table_footnote_patterns_loader import (
    load_title_patterns, load_label_patterns, load_footnote_patterns
)


TITLE_PATTERNS = load_title_patterns()
LABEL_PATTERNS = load_label_patterns()
FOOTNOTE_PATTERNS = load_footnote_patterns()


def _extract_label(text: str) -> Optional[str]:
    text = (text or "").strip()
    for pat in LABEL_PATTERNS:
        m = pat.match(text)
        if m:
            label = m.group(0).strip()
            label = re.sub(r"\s+", " ", label)
            label = re.sub(r"^(table|listing)", lambda m: m.group(1).capitalize(), label)
            return label
    return None


def _compute_level(label: Optional[str]) -> int:
    if not label:
        return 0
    parts = label.split(None, 1)
    number_part = parts[1] if len(parts) == 2 else parts[0]
    return number_part.count('.')


def _rtf_to_text(rtf_path: Path) -> str:
    # 朴素的 RTF 文本提取：去除控制词与分组，保留 \par 作为换行
    data = rtf_path.read_bytes()
    try:
        s = data.decode('utf-8', errors='ignore')
    except Exception:
        s = data.decode('latin-1', errors='ignore')
    # 将段落分隔转换为换行
    s = s.replace("\\par", "\n").replace("\\line", "\n")
    s = s.replace("\\tab", "\t")
    # 移除转义的 16 进制字符（简化处理）
    s = re.sub(r"\\'[0-9a-fA-F]{2}", " ", s)
    # 移除控制词（如 \\b、\\fs24 等）
    s = re.sub(r"\\[a-zA-Z]+(?:-?\d+)?\s?", "", s)
    # 移除分组的大括号
    s = s.replace('{', '').replace('}', '')
    # 归一化换行
    s = re.sub(r"\r\n|\r", "\n", s)
    # 压缩多行空白
    s = re.sub(r"\n{3,}", "\n\n", s)
    return s


class RTFFileParseCommand(Command):
    """
    简易 RTF 解析命令：
    - 逐行匹配标题模式，生成 TableItem；
    - 尝试收集紧随标题后的脚注行（基于 footnote_patterns），直到遇到下一个标题；
    - 不支持表格索引（table_index 始终为 None）。
    """

    def is_satisfied(self, context: Context) -> bool:
        return context.has_document()

    def execute(self, context: Context) -> Context:
        paths = context.resolve_document_paths(patterns=["*.rtf"])
        if not paths:
            # 若无 RTF 文件，直接返回，不记为错误（由条件控制是否运行）
            return context

        sections_out: List[Dict] = []
        for p in paths:
            txt = _rtf_to_text(Path(p))
            lines = [ln.strip() for ln in txt.splitlines()]
            current: Optional[TableItem] = None
            for idx, line in enumerate(lines):
                if not line:
                    continue
                # 新标题开始
                if any(pat.match(line) for pat in TITLE_PATTERNS):
                    if current:
                        d = asdict(current)
                        d["source_file"] = str(p)
                        sections_out.append(d)
                    label = _extract_label(line)
                    current = TableItem(
                        label=label,
                        title=line,
                        level=_compute_level(label),
                        section=label.split(None, 1)[1] if label else None,
                        title_indices=[idx],
                    )
                    continue
                # 收集脚注（仅当已有当前标题且匹配脚注规则）
                if current and any(pat.search(line) for pat in FOOTNOTE_PATTERNS):
                    current.add_footnote_index(idx)
                    current.append_footnote_text(line)
            # 收尾：追加最后一个段
            if current:
                d = asdict(current)
                d["source_file"] = str(p)
                sections_out.append(d)

        context.doc_type = "rtf"
        context.sections = sections_out
        context.processing_summary["rtf_title_table_footnote_partition"] = {
            "files_processed": len(paths),
            "sections_extracted": len(sections_out),
            "mode": "rtf_text_only",
        }
        return context


# 注册到命令注册表
CommandRegistry.register("RTFFileParseCommand", RTFFileParseCommand)