# -*- coding: utf-8 -*-
"""
统一配置与映射模块。
将需求类型、章节过滤、输出映射和拆分参数收敛到单一入口。
"""

from dataclasses import dataclass
from typing import Dict, List, Any


@dataclass
class RequirementTypeRule:
    key: str
    chinese_name: str
    prefix: str
    keywords: List[str]
    priority: int


class AppSettings:
    """从 config 读取并提供统一访问接口。"""

    TYPE_NAME_MAP = {
        "功能需求": "functional",
        "接口需求": "interface",
        "性能需求": "performance",
        "安全需求": "security",
        "可靠性需求": "reliability",
        "其他需求": "other",
    }

    DEFAULT_NON_REQUIREMENT_SECTIONS = [
        "标识",
        "系统概述",
        "文档概述",
        "引用文档",
        "合格性规定",
        "需求可追踪性",
        "注释",
        "附录",
        "范围",
        "概述",
    ]

    DEFAULT_TYPE_CHINESE = {
        "functional": "功能需求",
        "interface": "接口需求",
        "performance": "其他需求",
        "security": "其他需求",
        "reliability": "其他需求",
        "other": "其他需求",
    }

    DEFAULT_PREFIX = {
        "functional": "FR",
        "interface": "IR",
        "performance": "PR",
        "security": "SR",
        "reliability": "RR",
        "other": "OR",
    }

    DEFAULT_INTERFACE_SECTION_HINTS = [
        "接口描述",
        "接口需求",
        "接口要求",
        "外部接口",
        "内部接口",
        "i/o",
    ]

    DEFAULT_INTERFACE_TITLE_EXCLUDES = [
        "计算机通信需求",
        "通信需求",
        "通信要求",
    ]

    DEFAULT_FUNCTIONAL_SECTION_HINTS = [
        "功能需求",
        "功能要求",
    ]

    DEFAULT_OTHER_SECTION_HINTS = [
        "安全性需求",
        "保密性需求",
        "适应性需求",
        "环境需求",
        "资源需求",
        "质量",
        "设计约束",
        "培训需求",
        "软件保障",
        "验收",
        "交付",
        "包装",
        "通信需求",
        "计算机通信需求",
        "硬件环境",
        "软件环境",
        "运行环境",
    ]

    def __init__(self, config: Dict[str, Any] = None):
        self.config = config or {}

        document_cfg = self.config.get("document", {})
        self.non_requirement_sections = document_cfg.get(
            "non_requirement_sections", self.DEFAULT_NON_REQUIREMENT_SECTIONS
        )

        extraction_cfg = self.config.get("extraction", {})
        req_types_cfg = extraction_cfg.get("requirement_types", {})

        self.requirement_rules = self._build_rules(req_types_cfg)
        self.type_prefix = self._build_type_prefix(req_types_cfg)
        self.type_chinese = self._build_type_chinese(req_types_cfg)

        semantic_type_cfg = extraction_cfg.get("semantic_type_policy", {})
        self.interface_section_hints = [
            str(x).lower() for x in semantic_type_cfg.get("interface_section_hints", self.DEFAULT_INTERFACE_SECTION_HINTS)
        ]
        self.interface_title_excludes = [
            str(x).lower() for x in semantic_type_cfg.get("interface_title_excludes", self.DEFAULT_INTERFACE_TITLE_EXCLUDES)
        ]
        self.functional_section_hints = [
            str(x).lower() for x in semantic_type_cfg.get("functional_section_hints", self.DEFAULT_FUNCTIONAL_SECTION_HINTS)
        ]
        self.other_section_hints = [
            str(x).lower() for x in semantic_type_cfg.get("other_section_hints", self.DEFAULT_OTHER_SECTION_HINTS)
        ]

        splitter_cfg = extraction_cfg.get("splitter", {})
        self.splitter_max_sentence_len = int(splitter_cfg.get("max_sentence_len", 120))
        self.splitter_min_clause_len = int(splitter_cfg.get("min_clause_len", 12))
        self.splitter_enabled = bool(splitter_cfg.get("enabled", True))

        semantic_cfg = extraction_cfg.get("semantic_guard", {})
        self.semantic_guard_enabled = bool(semantic_cfg.get("enabled", True))
        self.preserve_condition_action_chain = bool(
            semantic_cfg.get("preserve_condition_action_chain", True)
        )
        self.preserve_alarm_chain = bool(semantic_cfg.get("preserve_alarm_chain", True))

        table_cfg = extraction_cfg.get("table_strategy", {})
        self.table_llm_semantic_enabled = bool(table_cfg.get("llm_semantic_enabled", True))
        self.sequence_table_merge = table_cfg.get("sequence_table_merge", "single_requirement")
        self.merge_time_series_rows_min = int(table_cfg.get("merge_time_series_rows_min", 3))
        self.table_skip_keywords = list(
            table_cfg.get(
                "skip_keywords",
                ["系统功能要求", "性能要求", "功能矩阵", "能力对照", "性能指标对照"],
            )
        )
        self.table_interface_keywords = list(
            table_cfg.get(
                "interface_keywords",
                ["接口", "interface", "输入输出", "I/O", "数据来源", "数据目的地", "来源", "目的地"],
            )
        )
        self.table_single_requirement_keywords = list(
            table_cfg.get(
                "single_requirement_keywords",
                ["硬件要求", "软件要求", "运行环境", "环境需求", "资源需求", "计算机资源"],
            )
        )

        rewrite_cfg = extraction_cfg.get("rewrite_policy", {})
        self.llm_light_rewrite_enabled = bool(rewrite_cfg.get("llm_light_rewrite_enabled", True))
        self.preserve_ratio_min = float(rewrite_cfg.get("preserve_ratio_min", 0.65))
        self.max_length_growth_ratio = float(rewrite_cfg.get("max_length_growth_ratio", 1.25))
        self.non_interface_max_edit_distance = int(rewrite_cfg.get("non_interface_max_edit_distance", 20))

        self.system_description_hints = list(
            extraction_cfg.get(
                "system_description_hints",
                ["系统描述", "功能描述", "概述", "示意图", "组成", "架构", "原理"],
            )
        )

        renumber_cfg = extraction_cfg.get("renumber_policy", {})
        self.renumber_enabled = bool(renumber_cfg.get("enabled", True))
        self.renumber_mode = renumber_cfg.get("mode", "section_continuous")

        dedup_cfg = extraction_cfg.get("dedup_policy", {})
        self.dedup_similarity_threshold = float(dedup_cfg.get("similarity_threshold", 0.88))
        self.enable_cross_section_dedup = bool(dedup_cfg.get("enable_cross_section_dedup", True))
        self.prefer_text_over_table = bool(dedup_cfg.get("prefer_text_over_table", True))

        interface_cfg = extraction_cfg.get("interface_policy", {})
        self.interface_unknown_fallback = str(interface_cfg.get("unknown_fallback", "未知"))

        normalization_cfg = extraction_cfg.get("normalization_policy", {})
        self.ocr_spacing_normalize = bool(normalization_cfg.get("ocr_spacing_normalize", True))

        fidelity_cfg = extraction_cfg.get("fidelity_policy", {})
        self.preserve_source_text_for_text_blocks = bool(
            fidelity_cfg.get("preserve_source_text_for_text_blocks", True)
        )

        punctuation_cfg = extraction_cfg.get("punctuation_policy", {})
        self.ensure_terminal_period = bool(punctuation_cfg.get("ensure_terminal_period", True))

    def _build_rules(self, req_types_cfg: Dict[str, Dict[str, Any]]) -> List[RequirementTypeRule]:
        rules: List[RequirementTypeRule] = []
        if not req_types_cfg:
            # 用默认两类保证兼容旧行为
            return [
                RequirementTypeRule(
                    key="interface",
                    chinese_name="接口需求",
                    prefix="IR",
                    keywords=["接口", "interface", "api", "串口", "通信", "CAN", "以太网"],
                    priority=1,
                ),
                RequirementTypeRule(
                    key="functional",
                    chinese_name="功能需求",
                    prefix="FR",
                    keywords=["功能", "控制", "处理", "监测", "显示"],
                    priority=2,
                ),
            ]

        for zh_name, item in req_types_cfg.items():
            key = self.TYPE_NAME_MAP.get(zh_name, "other")
            rules.append(
                RequirementTypeRule(
                    key=key,
                    chinese_name=zh_name,
                    prefix=item.get("prefix", self.DEFAULT_PREFIX.get(key, "FR")),
                    keywords=item.get("keywords", []),
                    priority=int(item.get("priority", 99)),
                )
            )

        return sorted(rules, key=lambda x: x.priority)

    def _build_type_prefix(self, req_types_cfg: Dict[str, Dict[str, Any]]) -> Dict[str, str]:
        mapping = dict(self.DEFAULT_PREFIX)
        for zh_name, key in self.TYPE_NAME_MAP.items():
            if zh_name in req_types_cfg:
                mapping[key] = req_types_cfg[zh_name].get("prefix", mapping[key])
        return mapping

    def _build_type_chinese(self, req_types_cfg: Dict[str, Dict[str, Any]]) -> Dict[str, str]:
        mapping = dict(self.DEFAULT_TYPE_CHINESE)
        for zh_name, key in self.TYPE_NAME_MAP.items():
            if zh_name in req_types_cfg:
                mapping[key] = zh_name
        return mapping

    def is_non_requirement_section(self, title: str) -> bool:
        return any(keyword in title for keyword in self.non_requirement_sections)

    def is_interface_semantic_title(self, title: str) -> bool:
        t = (title or "").strip().lower()
        if not t:
            return False

        excluded = any(x in t for x in self.interface_title_excludes)
        if excluded and "接口" not in t:
            return False

        return any(h in t for h in self.interface_section_hints)

    def is_functional_semantic_title(self, title: str) -> bool:
        t = (title or "").strip().lower()
        if not t:
            return False
        return any(h in t for h in self.functional_section_hints)

    def is_other_semantic_title(self, title: str) -> bool:
        t = (title or "").strip().lower()
        if not t:
            return False
        return any(h in t for h in self.other_section_hints)

    def detect_requirement_type(self, title: str, content: str) -> str:
        # 章节语义优先：接口仅由接口类章节触发；安全/保密/适应性等统一归其他需求。
        if self.is_interface_semantic_title(title):
            return "interface"
        if self.is_functional_semantic_title(title):
            return "functional"
        if self.is_other_semantic_title(title):
            return "other"

        combined_text = f"{title} {(content or '')[:500]}".lower()
        for rule in self.requirement_rules:
            if rule.key == "interface" and not self.is_interface_semantic_title(title):
                continue
            for keyword in rule.keywords:
                if keyword.lower() in combined_text:
                    if rule.key in {"performance", "security", "reliability", "other"}:
                        return "other"
                    return rule.key
        return "functional"
