"""
结果汇总与规范覆盖分析组件
"""
import json
from typing import Dict, List, Any, Set, Optional
import ast
import sys
from pathlib import Path

# 添加项目根目录到路径，支持相对导入
_root = Path(__file__).parent.parent
if str(_root) not in sys.path:
    sys.path.insert(0, str(_root))

from interfaces import IResultAnalyzer, IKeywordChecker
from utils.file_utils import read_csv, write_csv
from foundation.observability.logger.loggering import review_logger as logger
from foundation.observability.cachefiles import cache, CacheBaseDir


class ResultAnalyzer(IResultAnalyzer):
    """审查结果汇总分析器"""

    def __init__(self, spec_csv_path: str, keyword_checker: Optional[IKeywordChecker] = None):
        """
        Args:
            spec_csv_path: 规范 CSV 文件路径（Construction_Plan_Content_Specification.csv）
            keyword_checker: 关键词检查器（可选）
        """
        self.spec_csv_path = spec_csv_path
        self.keyword_checker = keyword_checker

    def process_results(self, results: List[Dict[str, Any]], specification:  Optional[Dict[str, List[Dict[str, str]]]] = None) -> List[Dict[str, Any]]:
        """
        按规则清洗审查结果，生成新的 JSON 列表

        - 新列表仅保留字段：chunk_id、section_label、chapter_classification、review_result
        - 如果 section_label 中包含 "->"（视为包含两段及以上标题），
          则遍历 review_result 的键名（即二级目录名称）：
            * 若键名未出现在 section_label 的字符串中，则将该键对应的值列表清空 []
        - 所有要点编号列表在块内部去重
        - 如果启用了关键词检查器，则对缺失的要点进行二次验证
        """
        processed: List[Dict[str, Any]] = []

        for item in results:
            chunk_id = item.get("chunk_id", "")
            section_label = item.get("section_label", "") or ""
            chapter_classification = item.get("chapter_classification", "") or ""
            review_result = item.get("review_result", {})
            content = item.get("content", "")

            if not isinstance(review_result, dict):
                review_result = {}

            new_review_result: Dict[str, List[int]] = {}

            has_multi_titles = "->" in section_label

            for key, value in review_result.items():
                # 只接受列表类型的要点编号
                points: List[int] = []
                if isinstance(value, list):
                    for v in value:
                        if isinstance(v, int):
                            points.append(v)
                        elif isinstance(v, str) and v.isdigit():
                            points.append(int(v))
                # 去重并排序
                points = sorted(set(points))

                if has_multi_titles:
                    # 标题中未出现该二级目录名，则清空
                    if key and key not in section_label:
                        new_review_result[key] = []
                    else:
                        new_review_result[key] = points
                else:
                    new_review_result[key] = points

            # 关键词二次检查（只过滤，不改变数据结构）
            if self.keyword_checker and specification:
                new_review_result = self.keyword_checker.filter_missing_points(
                    new_review_result, content, specification, chapter_classification
                )

            processed.append(
                {
                    "chunk_id": chunk_id,
                    "section_label": section_label,
                    "chapter_classification": chapter_classification,
                    "review_result": new_review_result,
                    "content": content
                }
            )

        return processed

    def build_spec_summary(
        self, processed_results: List[Dict[str, Any]], output_csv_path: str = None
    ) -> List[Dict[str, Any]]:
        """
        基于规范 CSV 与处理后的审查结果，生成规范要点覆盖汇总表

        - 从规范 CSV 读取原始行，增加三列：
            * 审查到的要点: 形如 [1, 2, 3]
            * 缺失的要点: 形如 [1, 3]
            * 要点来源:    形如 ["第五章 施工安全保证措施->一） 组织保证措施", ...]
        - 对于每个规范行(标签 + 二级目录)：
            * 从所有块中收集该标签 & 二级目录下出现的要点编号（不重复）
            * 根据"内容要点数量"推算缺失的要点编号
            * 将出现过要点的块的 section_label 作为来源去重记录
        """
        # 读取规范原始表（制表符分隔）
        spec_rows = read_csv(self.spec_csv_path, delimiter="\t")

        # 预处理：按 (标签, 二级目录) 聚合审查结果
        # key: (chapter_classification, level2)
        points_found_map: Dict[str, Set[int]] = {}
        sources_map: Dict[str, Set[str]] = {}
        content_map: Dict[str, str] = {}  # 二级目录的 content 映射
        section_label_map: Dict[str, str] = {}  # 二级目录的 section_label 映射
        # 一级章节的映射（作为后备，当找不到二级目录时使用）
        chapter_content_map: Dict[str, str] = {}  # 按 chapter_classification 索引
        chapter_section_label_map: Dict[str, str] = {}  # 按 chapter_classification 索引

        for item in processed_results:
            chapter_classification = (item.get("chapter_classification") or "").strip()
            section_label = (item.get("section_label") or "").strip()
            review_result = item.get("review_result", {}) or {}
            content = item.get("content", "")

            if not chapter_classification or not isinstance(review_result, dict):
                continue

            # 记录一级章节信息（作为后备）
            if chapter_classification not in chapter_content_map:
                chapter_content_map[chapter_classification] = content
                chapter_section_label_map[chapter_classification] = section_label
            else:
                # 如果已存在且当前内容非空，更新为最新的
                if content:
                    chapter_content_map[chapter_classification] = content
                    chapter_section_label_map[chapter_classification] = section_label

            # 截断来源标题：只保留前两段（按 "->" 分隔）
            if "->" in section_label:
                parts = [p.strip() for p in section_label.split("->") if p.strip()]
                if len(parts) >= 2:
                    source_label = "->".join(parts[:2])
                else:
                    source_label = parts[0] if parts else section_label
            else:
                source_label = section_label

            for level2_name, points in review_result.items():
                if not level2_name:
                    continue

                key = f"{chapter_classification}_{level2_name}"
                if key not in points_found_map:
                    points_found_map[key] = set()
                    sources_map[key] = set()
                    content_map[key] = ""  # 初始化 content
                    section_label_map[key] = ""  # 初始化 section_label

                if isinstance(points, list) and points:
                    for p in points:
                        if isinstance(p, int):
                            points_found_map[key].add(p)
                        elif isinstance(p, str) and p.isdigit():
                            points_found_map[key].add(int(p))
                    # 只要该块在该二级目录下有任何要点，就记录来源（截断后的标题）
                    sources_map[key].add(source_label)
                    # 记录 content 和 section_label（使用最后一个遇到的内容）
                    content_map[key] = content
                    section_label_map[key] = section_label

        # 根据规范逐行生成统计结果
        summary_rows: List[Dict[str, Any]] = []
        for row in spec_rows:
            tag = (row.get("标签") or "").strip()
            level2 = (row.get("二级目录") or "").strip()
            point_count_str = (row.get("内容要点数量") or "").strip()

            # 解析要点总数
            try:
                total_points = int(point_count_str)
            except (TypeError, ValueError):
                total_points = 0

            key = f"{tag}_{level2}"
            found_points = sorted(points_found_map.get(key, set()))

            if total_points > 0:
                missing_points = [
                    i for i in range(1, total_points + 1) if i not in found_points
                ]
            else:
                missing_points = []

            sources = sorted(sources_map.get(key, set())) if key in sources_map else []

            # 获取 content 和 section_label，优先使用二级目录映射，找不到则使用一级章节映射
            content = content_map.get(key, "")
            section_label = section_label_map.get(key, "")
            # 如果二级目录映射为空，使用一级章节映射作为后备
            if not content:
                content = chapter_content_map.get(tag, "")
            if not section_label:
                section_label = chapter_section_label_map.get(tag, "")

            # 组装输出行（在原规范行基础上增加三列）
            new_row = dict(row)
            new_row["审查到的要点"] = str(found_points)
            new_row["缺失的要点"] = str(missing_points)
            new_row["要点来源"] = str(sources)
            new_row['content'] = content
            new_row['section_label'] = section_label
            summary_rows.append(new_row)

        # 写出 CSV，使用 UTF-8-SIG 编码（write_csv 内部已固定为 utf-8-sig）
        # 使用逗号分隔符便于通用 CSV 工具查看
        if output_csv_path:
            write_csv(summary_rows, output_csv_path, delimiter=",")
        return summary_rows

    # 生成缺失要点的 JSON 列表，便于前端或其他系统直接消费
    def build_missing_issue_list(
        self, summary_rows: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """
        构建缺失要点的问题列表

        Args:
            summary_rows: 规范汇总行数据

        Returns:
            Dict: 审查结果字典，包含 response 字段的问题列表和必要的元数据
        """
        all_issues = []
        metadata = {}
        suorces_eum = {
            "basis": "编制依据",
            "overview": "工程概况",
            "plan": "施工计划",
            "technology": "施工工艺技术",
            "safety": "安全保证措施",
            "quality": "质量保证措施",
            "environment": "环境保证措施",
            "management": "施工管理及作业人员配备与分工",
            "acceptance": "验收要求",
            "other": "其他资料"
            }
        for row in summary_rows:
            level2 = (row.get("二级目录") or "").strip()
            requirement = (row.get("内容要求") or "").strip()
            reference_source = '《桥梁公司危险性较大工程管理实施细则（2025版）》'
            reason= f"参照：{reference_source} 中的内容要求，{row.get('section_label', '')}内容属于,专项施工方案内容要求中的 【{suorces_eum[row.get('标签', '')]}】 板块，应包含{requirement}"
            review_references = (row.get("依据") or "").strip()
            if level2 in row.get("content", ""):
                continue
            missing_points_raw = row.get("缺失的要点", "")
            missing_points = self._parse_list_field(missing_points_raw)
            if not missing_points:
                continue

            sources_raw = row.get("要点来源", "")
            #sources = self._parse_list_field(sources_raw)
            #location = "; ".join(map(str, sources)) if sources else ""

            requirement_list = requirement.split('：')[-1].split('；')
            missing_count = len(missing_points)
            section_label = row.get('section_label', '')
            level2_name = suorces_eum.get(row.get('标签', ''), '')
            
            # 获取缺失要点的具体内容
            missing_content_list = []
            for idx in missing_points:
                if 0 < idx <= len(requirement_list):
                    missing_content_list.append(f"{idx}.{requirement_list[idx-1]}")
            missing_content_text = '；'.join(missing_content_list)
            
            issue_point = f"【内容不完整】{section_label}的'{level2_name}'部分缺少{missing_count}个要点"
            suggestion = f"请补充'{level2_name}'的{','.join(map(str, missing_points))}内容：{missing_content_text}"
            risk_level = self._map_risk_level(len(missing_points))
            risk_level_std = "high" if "高" in risk_level else ("medium" if "中" in risk_level else "low")

            # 构建问题项并添加到列表（与参数合规审查格式一致）
            issue_item = {
                "check_item": "completeness_check",
                "chapter_code": row.get("标签", "completeness"),
                "check_item_code": f"{row.get('标签', 'completeness')}_completeness_check",
                "check_result": {
                    "issue_point": issue_point,
                    "location": row.get("section_label", ""),
                    "suggestion": suggestion,
                    "reason": f"根据《桥梁公司危险性较大工程管理实施细则（2025版）》，{section_label}的'{level2_name}'应包含：{requirement}。当前缺失：{missing_content_text}",
                    "risk_level": risk_level
                },
                "exist_issue": True,
                "risk_info": {"risk_level": risk_level_std}
            }
            all_issues.append(issue_item)
            # with open("temp/construction_review/document_temp/missing_points.json", "w", encoding="utf-8") as f:
            #     json.dump(all_issues, f, ensure_ascii=False, indent=4)
            cache.document_temp(all_issues, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
            if not metadata:
                metadata = {
                    "review_location_label": row.get("section_label", ""),
                    "chapter_code": row.get("标签", ""),
                    "original_content": row.get("content", "")
                }
                cache.document_temp(metadata, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
        logger.debug(f"build_missing_issue_list_all_issues:{len(all_issues)}")
        # 返回包含问题和元数据的字典，由外层统一格式化
        return {
            "response": all_issues,
            **metadata
        }

    @staticmethod
    def _parse_list_field(value: Any) -> List[Any]:
        """把 CSV 中的列表字符串安全转回列表"""
        if isinstance(value, list):
            return value
        if not value:
            return []
        try:
            parsed = ast.literal_eval(value)
            if isinstance(parsed, list):
                return parsed
        except Exception:
            return []
        return []

    @staticmethod
    def _map_risk_level(missing_count: int) -> str:
        """根据缺失要点数量映射风险等级"""
        if missing_count >= 3:
            return "高风险"
        if missing_count == 2:
            return "中风险"
        return "低风险"
