"""
内容块分类模块（二级和三级分类）

对已经完成一级分类的内容块进行二级和三级分类
"""

from __future__ import annotations

import asyncio
import csv
import json
import re
from collections import OrderedDict
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

from foundation.infrastructure.config.config import config_handler
from foundation.observability.logger.loggering import review_logger as logger
from foundation.ai.agent.generate.model_generate import generate_model_client

from ..config.provider import default_config_provider
from ..utils.prompt_loader import PromptLoader


# ==================== 二级分类本地规则 ====================
# 结构: {一级代码: [(关键词模式, 二级代码, 二级中文名), ...]}
SECONDARY_CLASSIFICATION_RULES: Dict[str, List[Tuple[str, str, str]]] = {
    "basis": [
        (r"法律|法规|规章|政策|条文", "LawsAndRegulations", "法律法规"),
        (r"标准|规范|GB|JTG|CJJ|Q/CR", "StandardsAndSpecifications", "标准规范"),
        (r"文件|制度|程序|办法|规定|路桥|集团|公司", "DocumentSystems", "文件制度"),
        (r"编制.*原则|原则|程序|功能|合同|力量", "CompilationPrinciples", "编制原则"),
        (r"编制.*范围|范围|施工.*工艺", "CompilationScope", "编制范围"),
    ],
    "overview": [
        (r"设计.*概况|概况|简介|介绍|工程.*说明", "DesignSummary", "设计概况"),
        (r"地质|水文|气象|气候|地下.*水", "GeologyWeather", "工程地质与水文气象"),
        (r"周边.*环境|环境|位置.*关系|相邻|距离|管线|高压", "Surroundings", "周边环境"),
        (r"平面.*布置|立面|临时.*设施|拌和|材料|便道|水电", "LayoutPlan", "施工平面及立面布置"),
        (r"工期|质量.*目标|安全.*目标|环境.*目标|目标", "RequirementsTech", "施工要求和技术保证条件"),
        (r"风险|危险源|危害|隐患|风险.*辨识|分级", "RiskLevel", "风险辨别与分级"),
        (r"参建.*单位|建设.*单位|设计.*单位|监理|施工.*单位", "Stakeholders", "参建各方责任主体单位"),
    ],
    "plan": [
        (r"进度.*计划|进度|横道图|甘特图|节点|工期", "Schedule", "施工进度计划"),
        (r"材料.*计划|材料|物资|钢筋|混凝土|水泥", "Materials", "施工材料计划"),
        (r"设备.*计划|设备|机械|机具|吊装|起重|泵车", "Equipment", "施工设备计划"),
        (r"劳动力|人员|工种|工人|班组|劳务", "Workforce", "劳动力计划"),
        (r"安全.*费用|安全.*投入|安全.*经费", "SafetyCost", "安全生产费用使用计划"),
    ],
    "technology": [
        (r"施工.*方法|工艺.*选择|主要.*方法", "MethodsOverview", "主要施工方法概述"),
        (r"技术.*参数|材料.*规格|设备.*名称", "TechParams", "技术参数"),
        (r"工艺.*流程|施工.*流程|工序|流程.*图", "ProcessFlow", "工艺流程"),
        (r"操作.*要点|施工.*要点|注意.*事项", "OperationPoints", "操作要点"),
        (r"检查.*要求|质量.*检查|验收.*标准", "InspectionRequirements", "检查要求"),
    ],
    "safety": [
        (r"安全.*目标|目标", "SafetyGoals", "安全目标"),
        (r"危险源|危害|风险|LEC|辨识", "SafetyHazards", "危险源辨识"),
        (r"组织.*保证|安全.*组织|管理.*机构|领导小组", "Organization", "组织保证措施"),
        (r"技术.*措施|安全.*技术|防护|防护.*措施", "SafetyTech", "技术措施"),
        (r"监测|监控|量测|观测|预警", "Monitoring", "监测监控"),
        (r"应急|预案|救援|抢险|处置", "Emergency", "应急处置措施"),
    ],
    "quality": [
        (r"质量.*目标|目标|质量.*标准", "QualityGoals", "质量目标"),
        (r"质量.*组织|组织.*保证|管理.*机构|质量.*体系", "QualityOrg", "质量组织保证措施"),
        (r"技术.*措施|质量.*技术|控制.*措施|质量保证.*措施", "QualityTech", "技术措施"),
        (r"检查.*验收|验收.*程序|质量.*检查|三检", "QualityInspection", "检查验收"),
        (r"质量.*保修|保修.*期|缺陷.*责任", "Warranty", "质量保修"),
    ],
    "environment": [
        (r"环境.*目标|环保.*目标|文明.*施工|绿色.*施工", "EnvGoals", "环境目标"),
        (r"环保.*组织|环境.*组织|管理.*机构", "EnvOrg", "环境保护组织机构"),
        (r"环保.*措施|环境.*技术|扬尘|噪声|污水|废弃物", "EnvTech", "技术措施"),
        (r"节能|减排|资源.*利用|绿色.*建材", "GreenConstruction", "绿色施工措施"),
    ],
    "management": [
        (r"管理.*人员|施工.*管理.*人员|项目.*经理|项目.*总工|名单", "Managers", "施工管理人员"),
        (r"专职.*安全|安全.*总监|安全员|C证|考核.*合格", "SafetyStaff", "专职安全生产管理人员"),
        (r"特种.*作业|特种.*人员|电工|焊工|架子工|起重", "SpecialWorkers", "特种作业人员"),
        (r"其他.*作业|工种.*数量|作业.*人员|分包.*人员", "OtherWorkers", "其它作业人员"),
    ],
    "acceptance": [
        (r"验收.*标准|标准|规范|依据", "Standards", "验收标准"),
        (r"验收.*程序|程序|流程|步骤", "Procedures", "验收程序"),
        (r"验收.*人员|人员|组织|验收.*组|专家", "Personnel", "验收人员"),
        (r"验收.*条件|条件|前提|要求", "Conditions", "验收条件"),
    ],
    "other": [
        (r"计算|验算|受力|稳定性|强度|刚度", "Calculations", "计算书"),
        (r"图纸|附图|附表|平面.*图|立面.*图|剖面.*图", "Drawings", "图纸"),
    ],
}


def classify_secondary_local(section_title: str, first_category_code: str) -> Optional[Tuple[str, str, float]]:
    """
    本地规则分类二级标题

    返回: (二级代码, 二级中文名, 置信度) 或 None
    """
    if not section_title or not first_category_code:
        return None

    rules = SECONDARY_CLASSIFICATION_RULES.get(first_category_code, [])
    if not rules:
        return None

    title = section_title.strip()

    for pattern, code, cn in rules:
        if re.search(pattern, title, re.IGNORECASE):
            logger.debug(f"[二级本地分类] '{title}' -> {cn} ({code})")
            return code, cn, 0.85

    return None

# 延迟导入新的三级分类器（避免循环导入）
_LLM_CONTENT_CLASSIFIER = None


def _get_llm_content_classifier():
    """延迟导入 LLMContentClassifier"""
    global _LLM_CONTENT_CLASSIFIER
    if _LLM_CONTENT_CLASSIFIER is None:
        from ...reviewers.utils.llm_content_classifier_v2 import (
            LLMContentClassifier,
            ClassifierConfig
        )
        _LLM_CONTENT_CLASSIFIER = (LLMContentClassifier, ClassifierConfig)
    return _LLM_CONTENT_CLASSIFIER


def _extract_json(text: str) -> Optional[Dict[str, Any]]:
    """从字符串中提取第一个有效 JSON 对象"""
    for pattern in [r"```json\s*(\{.*?})\s*```", r"```\s*(\{.*?})\s*```"]:
        m = re.search(pattern, text, re.DOTALL)
        if m:
            try:
                return json.loads(m.group(1))
            except json.JSONDecodeError:
                pass
    try:
        for candidate in re.findall(r"(\{.*?\})", text, re.DOTALL):
            try:
                return json.loads(candidate)
            except json.JSONDecodeError:
                pass
    except Exception:
        pass
    return None


class ChunkClassifier:
    """内容块分类器（二级和三级分类）"""

    def __init__(self):
        """初始化分类器"""
        self._cfg = default_config_provider
        self._concurrency = int(config_handler.get("llm_keywords", "CONCURRENT_WORKERS", "20"))

        # 初始化提示词加载器
        self.prompt_loader = PromptLoader()

        # 加载CSV分类标准
        self._load_classification_standards()

    def _load_classification_standards(self):
        """从CSV文件加载二级和三级分类标准"""
        csv_file = Path(__file__).parent.parent / "config" / "StandardCategoryTable.csv"

        if not csv_file.exists():
            raise FileNotFoundError(f"分类标准CSV文件不存在: {csv_file}")

        # 结构: {first_code: {second_code: {second_cn, second_focus, third_items: [{third_code, third_cn, third_focus}]}}}
        self.classification_tree: Dict[str, Dict[str, Any]] = {}

        with csv_file.open("r", encoding="utf-8-sig") as f:
            reader = csv.DictReader(f)
            for row in reader:
                first_code = (row.get("first_code") or "").strip()
                first_cn = (row.get("first_name") or "").strip()
                second_code = (row.get("second_code") or "").strip()
                second_cn = (row.get("second_name") or "").strip()
                second_focus = (row.get("second_focus") or "").strip()
                third_code = (row.get("third_code") or "").strip()
                third_cn = (row.get("third_name") or "").strip()
                third_focus = (row.get("third_focus") or "").strip()

                if not first_code or not second_code:
                    continue

                # 初始化一级类别
                if first_code not in self.classification_tree:
                    self.classification_tree[first_code] = {}

                # 初始化二级类别
                if second_code not in self.classification_tree[first_code]:
                    self.classification_tree[first_code][second_code] = {
                        "second_cn": second_cn,
                        "second_focus": second_focus,
                        "third_items": []
                    }

                # 添加三级类别（如果存在）
                if third_code and third_cn:
                    self.classification_tree[first_code][second_code]["third_items"].append({
                        "third_code": third_code,
                        "third_cn": third_cn,
                        "third_focus": third_focus
                    })

    def _build_secondary_standards(self, first_category_code: str) -> tuple[str, dict]:
        """
        构建二级分类标准文本

        返回:
            (标准文本, 索引映射字典)
        """
        if first_category_code not in self.classification_tree:
            return "（无二级分类标准）", {}

        standards_lines = ["    0. 非标准项 - 不符合以下任何类别"]
        index_mapping = {0: ("非标准项", "non_standard")}

        for idx, (second_code, second_data) in enumerate(self.classification_tree[first_category_code].items(), 1):
            second_cn = second_data["second_cn"]
            second_focus = second_data["second_focus"]

            # 保存索引映射
            index_mapping[idx] = (second_cn, second_code)

            if second_focus and second_focus != "NULL":
                standards_lines.append(f"    {idx}. {second_cn} - 关注点：{second_focus}")
            else:
                standards_lines.append(f"    {idx}. {second_cn}")

        return "\n".join(standards_lines) if standards_lines else "（无二级分类标准）", index_mapping

    def _build_tertiary_standards(self, first_category_code: str, second_category_code: str) -> tuple[str, dict]:
        """
        构建三级分类标准文本

        返回:
            (标准文本, 索引映射字典)
        """
        if first_category_code not in self.classification_tree:
            return "（无三级分类标准）", {}

        if second_category_code not in self.classification_tree[first_category_code]:
            return "（无三级分类标准）", {}

        third_items = self.classification_tree[first_category_code][second_category_code]["third_items"]

        if not third_items:
            return "（无三级分类标准）", {}

        standards_lines = ["    0. 非标准项 - 不符合以下任何类别"]
        index_mapping = {0: ("非标准项", "non_standard")}

        for idx, third_item in enumerate(third_items, 1):
            third_cn = third_item["third_cn"]
            third_code = third_item["third_code"]
            third_focus = third_item["third_focus"]

            # 保存索引映射
            index_mapping[idx] = (third_cn, third_code)

            if third_focus and third_focus != "NULL":
                standards_lines.append(f"    {idx}. {third_cn} - 关注点：{third_focus}")
            else:
                standards_lines.append(f"    {idx}. {third_cn}")

        return "\n".join(standards_lines), index_mapping

    # 默认模型（三级分类会从 model_setting.yaml 动态加载）
    DEFAULT_MODEL = "qwen3_5_122b_a10b"

    # 二级分类模型（从 model_setting.yaml 动态加载，配置 key: doc_classification_secondary）
    @property
    def SECONDARY_MODEL(self) -> str:
        """二级分类模型，从 model_setting.yaml 读取配置"""
        try:
            from foundation.ai.models.model_config_loader import get_model_for_function
            model = get_model_for_function("doc_classification_secondary")
            if model:
                return model
        except Exception as e:
            logger.debug(f"加载二级分类模型配置失败: {e}")
        return "qwen3_5_35b_a3b"  # 兜底默认值

    async def _call_llm_once(
        self,
        system_prompt: str,
        user_prompt: str,
        model_name: Optional[str] = None
    ) -> Optional[Dict[str, Any]]:
        """
        单次异步 LLM 调用（使用统一的 GenerateModelClient）

        参数:
            system_prompt: 系统提示词
            user_prompt: 用户提示词
            model_name: 模型名称，默认使用 DEFAULT_MODEL

        失败返回 None，由调用方决定处理逻辑
        """
        if model_name is None:
            model_name = self.DEFAULT_MODEL

        try:
            content = await generate_model_client.get_model_generate_invoke(
                trace_id="chunk_classifier",
                system_prompt=system_prompt,
                user_prompt=user_prompt,
                model_name=model_name,
            )
            result = _extract_json(content)
            return result if result is not None else {"raw_content": content}
        except Exception as e:
            logger.error(f"[ChunkClassifier] LLM 调用失败: {e}")
            return None

    async def _batch_call_llm(
        self,
        requests: List[tuple],  # [(system_prompt, user_prompt), ...]
        model_name: Optional[str] = None,
    ) -> List[Optional[Dict[str, Any]]]:
        """
        并发批量调用 LLM（带信号量控制）

        参数:
            requests: 请求列表，每个元素是 (system_prompt, user_prompt) 元组
            model_name: 指定模型名称，None则使用默认模型

        返回:
            结果列表，与输入请求一一对应
        """
        semaphore = asyncio.Semaphore(self._concurrency)

        async def bounded_call(system_prompt: str, user_prompt: str):
            async with semaphore:
                return await self._call_llm_once(system_prompt, user_prompt, model_name)

        tasks = [bounded_call(sp, up) for sp, up in requests]
        return list(await asyncio.gather(*tasks))

    async def classify_chunks_secondary_async(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        异步对chunks进行二级分类

        参数:
            chunks: 已完成一级分类的chunk列表

        返回:
            添加了二级分类字段的chunk列表
        """
        logger.info(f"正在对 {len(chunks)} 个内容块进行二级分类...")

        # 准备LLM请求
        llm_requests = []
        valid_chunks = []
        index_mappings = []  # 保存每个请求对应的索引映射

        for chunk in chunks:
            first_category_code = chunk.get("chapter_classification", "")
            chunk_title = chunk.get("section_label", "")
            hierarchy_path = " -> ".join(chunk.get("hierarchy_path", []))
            content = chunk.get("review_chunk_content", "")
            content_preview = content[:300] if content else ""

            # 获取一级分类的中文名称
            first_category_cn = self._get_first_category_cn(first_category_code)

            # 构建二级分类标准（返回标准文本和索引映射）
            secondary_standards, index_mapping = self._build_secondary_standards(first_category_code)

            if secondary_standards == "（无二级分类标准）":
                # 如果没有二级分类标准，跳过
                chunk["secondary_category_cn"] = "无"
                chunk["secondary_category_code"] = "none"
                continue

            # 渲染提示词
            prompt = self.prompt_loader.render(
                "chunk_secondary_classification",
                first_category=first_category_cn,
                chunk_title=chunk_title,
                hierarchy_path=hierarchy_path,
                content_preview=content_preview,
                secondary_standards=secondary_standards
            )

            llm_requests.append((prompt["system"], prompt["user"]))
            valid_chunks.append(chunk)
            index_mappings.append(index_mapping)

        if not llm_requests:
            logger.info("所有内容块都没有二级分类标准，跳过二级分类")
            return chunks

        # === 阶段1: 本地规则分类 ===
        local_classified = []  # (chunk, code, cn) 或 None
        need_llm_indices = []  # 需要LLM的索引

        for idx, chunk in enumerate(valid_chunks):
            first_code = chunk.get("chapter_classification", "")
            section_title = chunk.get("section_label", "")

            # 尝试本地分类
            local_result = classify_secondary_local(section_title, first_code)

            if local_result:
                code, cn, confidence = local_result
                local_classified.append((chunk, code, cn, confidence, "local"))
                logger.debug(f"[二级本地分类] '{section_title}' -> {cn}")
            else:
                local_classified.append((chunk, None, None, 0.0, "need_llm"))
                need_llm_indices.append(idx)

        logger.info(f"[二级分类] 本地规则分类 {len(local_classified) - len(need_llm_indices)} 个, 需要LLM {len(need_llm_indices)} 个")

        # === 阶段2: LLM分类（仅对需要的）===
        if need_llm_indices:
            llm_requests_filtered = [llm_requests[i] for i in need_llm_indices]
            # 二级分类使用轻量级35B模型以提高速度
            llm_results = await self._batch_call_llm(llm_requests_filtered, model_name=self.SECONDARY_MODEL)

            # 映射回结果
            for i, idx in enumerate(need_llm_indices):
                llm_result = llm_results[i] if i < len(llm_results) else None
                chunk = valid_chunks[idx]
                index_mapping = index_mappings[idx]

                if llm_result and isinstance(llm_result, dict):
                    category_index = llm_result.get("category_index")

                    if isinstance(category_index, int) and category_index in index_mapping:
                        secondary_cn, secondary_code = index_mapping[category_index]
                        local_classified[idx] = (chunk, secondary_code, secondary_cn, 0.8, "llm")
                    else:
                        # LLM返回无效，使用非标准项
                        local_classified[idx] = (chunk, "non_standard", "非标准项", 0.0, "llm_failed")
                else:
                    # LLM调用失败
                    local_classified[idx] = (chunk, "non_standard", "非标准项", 0.0, "llm_failed")

        # === 阶段3: 写入结果 ===
        for chunk, code, cn, confidence, source in local_classified:
            chunk["secondary_category_code"] = code
            chunk["secondary_category_cn"] = cn

        logger.info("二级分类完成！")
        return chunks

    async def classify_chunks_tertiary_async(
        self,
        chunks: List[Dict[str, Any]],
        use_enhanced_classifier: bool = True,
        classifier_config: Optional[Any] = None,
        progress_callback: Optional[Any] = None
    ) -> List[Dict[str, Any]]:
        """
        异步对chunks进行三级分类

        参数:
            chunks: 已完成二级分类的chunk列表
            use_enhanced_classifier: 是否使用增强型分类器（行级细粒度、多分类、Embedding优化）
                - True: 使用新的 llm_content_classifier_v2（推荐）
                - False: 使用原有逐chunk分类方式
            classifier_config: 增强型分类器的配置对象（ClassifierConfig），为None时使用默认配置
            progress_callback: 进度回调函数 (completed, total, section_name, success) -> None，支持 async

        返回:
            添加了三级分类字段的chunk列表

        新增字段（use_enhanced_classifier=True时）:
            - tertiary_category_code: 三级分类代码
            - tertiary_category_cn: 三级分类名称
            - tertiary_classification_details: 行级分类详情列表，每个条目包含:
                - third_category_code: 三级分类代码
                - third_category_name: 三级分类名称
                - start_line: 起始行号
                - end_line: 结束行号
                - content: 原文内容
        """
        if use_enhanced_classifier:
            return await self._classify_chunks_tertiary_enhanced(chunks, classifier_config, progress_callback)
        else:
            return await self._classify_chunks_tertiary_legacy(chunks)

    async def _classify_chunks_tertiary_enhanced(
        self,
        chunks: List[Dict[str, Any]],
        config: Optional[Any] = None,
        progress_callback: Optional[Any] = None
    ) -> List[Dict[str, Any]]:
        """
        使用增强型分类器进行三级分类

        特点：
        - 行级细粒度分类
        - 支持一个段落包含多个三级分类
        - Embedding 相似度优化（跳过明显对应的段落）
        - 全局行号支持
        """
        logger.info(f"正在使用增强型分类器对 {len(chunks)} 个内容块进行三级分类... 特点: 行级细粒度 | 多分类支持 | Embedding优化")

        try:
            LLMContentClassifier, ClassifierConfig = _get_llm_content_classifier()
        except ImportError as e:
            logger.warning(f"无法导入增强型分类器，回退到传统方式: {e}")
            return await self._classify_chunks_tertiary_legacy(chunks)

        # 创建分类器实例
        if config is None:
            config = ClassifierConfig()
            # 使用与二级分类相同的并发度
            config.max_concurrent_requests = self._concurrency

            # 从全局配置加载模型和thinking模式
            try:
                from foundation.ai.models.model_config_loader import get_model_for_function, get_thinking_mode_for_function
                config.model = get_model_for_function("doc_classification_tertiary")
                config.enable_thinking = get_thinking_mode_for_function("doc_classification_tertiary") or False
                logger.info(f"三级分类配置 - 并发度: {config.max_concurrent_requests}, 模型: {config.model}, thinking: {config.enable_thinking}")
            except Exception as e:
                logger.warning(f"加载模型配置失败，使用默认配置: {e}")
                config.model = "qwen3_5_35b_a3b"
                config.enable_thinking = False

        classifier = LLMContentClassifier(config)

        # 调用增强型分类器
        updated_chunks = await classifier.classify_chunks(chunks, progress_callback=progress_callback)

        return updated_chunks

    async def _classify_chunks_tertiary_legacy(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        传统三级分类方式（逐chunk分类）

        每个chunk只能属于一个三级分类
        """
        logger.info(f"正在对 {len(chunks)} 个内容块进行三级分类...")

        # 准备LLM请求
        llm_requests = []
        valid_chunks = []
        index_mappings = []  # 保存每个请求对应的索引映射

        for chunk in chunks:
            first_category_code = chunk.get("chapter_classification", "")
            second_category_code = chunk.get("secondary_category_code", "")
            second_category_cn = chunk.get("secondary_category_cn", "")
            chunk_title = chunk.get("section_label", "")
            content = chunk.get("review_chunk_content", "")
            content_preview = content[:300] if content else ""

            # 获取一级分类的中文名称
            first_category_cn = self._get_first_category_cn(first_category_code)

            # 构建三级分类标准（返回标准文本和索引映射）
            tertiary_standards, index_mapping = self._build_tertiary_standards(first_category_code, second_category_code)

            if tertiary_standards == "（无三级分类标准）":
                # 如果没有三级分类标准，跳过
                chunk["tertiary_category_cn"] = "无"
                chunk["tertiary_category_code"] = "none"
                continue

            # 渲染提示词
            prompt = self.prompt_loader.render(
                "chunk_tertiary_classification",
                first_category=first_category_cn,
                secondary_category=second_category_cn,
                chunk_title=chunk_title,
                content_preview=content_preview,
                tertiary_standards=tertiary_standards
            )

            llm_requests.append((prompt["system"], prompt["user"]))
            valid_chunks.append(chunk)
            index_mappings.append(index_mapping)

        if not llm_requests:
            logger.info("所有内容块都没有三级分类标准，跳过三级分类")
            return chunks

        # 批量异步调用LLM API
        llm_results = await self._batch_call_llm(llm_requests)

        # 处理分类结果
        for chunk, llm_result, index_mapping in zip(valid_chunks, llm_results, index_mappings):
            if llm_result and isinstance(llm_result, dict):
                category_index = llm_result.get("category_index")

                # 验证索引并映射到类别
                if isinstance(category_index, int) and category_index in index_mapping:
                    tertiary_cn, tertiary_code = index_mapping[category_index]
                    chunk["tertiary_category_cn"] = tertiary_cn
                    chunk["tertiary_category_code"] = tertiary_code
                else:
                    # 索引无效，归类为非标准项
                    logger.warning(f"LLM返回的索引 {category_index} 无效，归类为'非标准项'")
                    chunk["tertiary_category_cn"] = "非标准项"
                    chunk["tertiary_category_code"] = "non_standard"
            else:
                chunk["tertiary_category_cn"] = "非标准项"
                chunk["tertiary_category_code"] = "non_standard"

        logger.info("三级分类完成！")
        return chunks

    def _get_first_category_cn(self, first_category_code: str) -> str:
        """获取一级分类的中文名称"""
        category_mapping = {
            "basis": "编制依据",
            "overview": "工程概况",
            "plan": "施工计划",
            "technology": "施工工艺技术",
            "safety": "安全保证措施",
            "quality": "质量保证措施",
            "environment": "环境保证措施",
            "management": "施工管理及作业人员配备与分工",
            "acceptance": "验收要求",
            "other": "其他资料",
            "non_standard": "非标准项"
        }
        return category_mapping.get(first_category_code, first_category_code)

    def classify_chunks_secondary(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """同步包装：二级分类"""
        try:
            return asyncio.run(self.classify_chunks_secondary_async(chunks))
        except RuntimeError:
            raise RuntimeError("请使用 await classify_chunks_secondary_async")

    def classify_chunks_tertiary(
        self,
        chunks: List[Dict[str, Any]],
        use_enhanced_classifier: bool = True,
        classifier_config: Optional[Any] = None
    ) -> List[Dict[str, Any]]:
        """同步包装：三级分类

        Args:
            chunks: 已完成二级分类的chunk列表
            use_enhanced_classifier: 是否使用增强型分类器（默认True）
            classifier_config: 增强型分类器配置（可选）
        """
        try:
            return asyncio.run(self.classify_chunks_tertiary_async(
                chunks,
                use_enhanced_classifier=use_enhanced_classifier,
                classifier_config=classifier_config
            ))
        except RuntimeError:
            raise RuntimeError("请使用 await classify_chunks_tertiary_async")