"""
审查结果逆向映射器

将云端审查意见中的泛化占位符还原为真实工程术语，生成最终审查报告。

根据 wlast.md 文档第6.3.3节设计
"""

import re
import logging
from typing import Dict, Any, Optional, Tuple
from dataclasses import dataclass

from .dict_manager import DictManager

logger = logging.getLogger(__name__)


@dataclass
class RemapResult:
    """映射结果"""
    original_response: str  # 原始响应（脱敏状态）
    remapped_response: str  # 还原后的响应（含真实术语）
    mapping_summary: Dict[str, int]  # 映射统计
    errors: list  # 错误信息


class ResultRemapper:
    """审查结果逆向映射器

    功能：
    1. 实体逆向替换（人名、企业名、工程实体）
    2. 坐标逆向转换（相对桩号 -> 绝对桩号）
    3. 保持审查意见语义不变

    示例：
      输入: "[项目经理A] 在 [1号特大桥] K0+500 处发现安全隐患"
      输出: "张三 在 映雪特大桥 D1K86+779.91 处发现安全隐患"
    """

    def __init__(self):
        """初始化映射器"""
        self.dict_manager = DictManager()

    async def remap(self, cloud_response: str, task_id: str,
                    remap_coordinate: bool = True) -> RemapResult:
        """将云端审查意见中的泛化词汇映射回真实工程术语

        Args:
            cloud_response: 云端审查返回的文本
            task_id: 文档脱敏时返回的任务ID
            remap_coordinate: 是否还原相对桩号

        Returns:
            RemapResult: 映射结果
        """
        errors = []

        # 1. 加载脱敏字典
        full_dict = await self.dict_manager.load(task_id)
        if not full_dict:
            error_msg = f"找不到脱敏字典: {task_id}"
            logger.error(f"[ResultRemapper] {error_msg}")
            return RemapResult(
                original_response=cloud_response,
                remapped_response=cloud_response,
                mapping_summary={},
                errors=[error_msg]
            )

        mapping_dict = full_dict.get("mappings", {})
        result = cloud_response

        # 2. 统计信息
        summary = {
            "person_mapped": 0,
            "entity_mapped": 0,
            "company_mapped": 0,
            "coordinate_mapped": 0,
            "total_replacements": 0
        }

        # 3. 人员逆向替换
        persons = mapping_dict.get("persons", [])
        for person in persons:
            original = person.get("masked", "")
            real_name = person.get("original", "")
            if original and original in result:
                count = result.count(original)
                result = result.replace(original, real_name)
                summary["person_mapped"] += count
                summary["total_replacements"] += count
                logger.debug(f"[ResultRemapper] 人员映射: {original} -> {real_name}")

        # 4. 工程实体逆向替换
        entities = mapping_dict.get("entities", [])
        for entity in entities:
            original = entity.get("masked", "")
            real_name = entity.get("original", "")
            if original and original in result:
                count = result.count(original)
                result = result.replace(original, real_name)
                summary["entity_mapped"] += count
                summary["total_replacements"] += count
                logger.debug(f"[ResultRemapper] 实体映射: {original} -> {real_name}")

        # 5. 企业/单位逆向替换
        companies = mapping_dict.get("companies", [])
        for company in companies:
            original = company.get("masked", "")
            real_name = company.get("original", "")
            if original and original in result:
                count = result.count(original)
                result = result.replace(original, real_name)
                summary["company_mapped"] += count
                summary["total_replacements"] += count
                logger.debug(f"[ResultRemapper] 企业映射: {original} -> {real_name}")

        # 6. 坐标逆向转换
        if remap_coordinate:
            coord_info = mapping_dict.get("coordinates", {})
            base_point = coord_info.get("base_point")
            mappings = coord_info.get("mappings", {})

            if base_point and mappings:
                result, coord_count = self._remap_coordinates(result, mappings, base_point)
                summary["coordinate_mapped"] = coord_count
                summary["total_replacements"] += coord_count

        # 7. 项目名称还原（如果有）
        project_info = mapping_dict.get("project_name", {})
        if project_info:
            masked = project_info.get("masked", "")
            original = project_info.get("original", "")
            if masked and masked in result:
                count = result.count(masked)
                result = result.replace(masked, original)
                summary["total_replacements"] += count

        logger.info(f"[ResultRemapper] 映射完成: {summary}")

        return RemapResult(
            original_response=cloud_response,
            remapped_response=result,
            mapping_summary=summary,
            errors=errors
        )

    def _remap_coordinates(self, text: str, mappings: Dict[str, str],
                           base_point: str) -> Tuple[str, int]:
        """将相对桩号还原为绝对桩号

        Args:
            text: 待处理的文本
            mappings: 原始->相对的映射字典
            base_point: 基准点

        Returns:
            (处理后的文本, 替换次数)
        """
        count = 0
        result = text

        # 匹配相对桩号格式 K{n}+{m}
        relative_pattern = re.compile(r'K(\d+)\+(\d{3})')

        def replace_coordinate(match):
            nonlocal count
            km = int(match.group(1))
            meter = int(match.group(2))

            # 查找对应的绝对坐标
            for original, relative in mappings.items():
                if relative == match.group(0):
                    count += 1
                    return original

            # 如果没有找到精确匹配，尝试计算
            # 这里简化处理，实际可能需要更复杂的坐标解析
            return match.group(0)

        result = relative_pattern.sub(replace_coordinate, result)
        return result, count

    async def remap_batch(self, responses: list, task_id: str,
                          remap_coordinate: bool = True) -> list:
        """批量映射多个响应

        Args:
            responses: 响应列表，每项为 (response_id, response_text)
            task_id: 任务ID
            remap_coordinate: 是否还原坐标

        Returns:
            映射后的结果列表
        """
        results = []
        for response_id, response_text in responses:
            try:
                remap_result = await self.remap(response_text, task_id, remap_coordinate)
                results.append({
                    "response_id": response_id,
                    "original": response_text,
                    "remapped": remap_result.remapped_response,
                    "summary": remap_result.mapping_summary
                })
            except Exception as e:
                logger.error(f"[ResultRemapper] 批量映射失败 {response_id}: {e}")
                results.append({
                    "response_id": response_id,
                    "original": response_text,
                    "remapped": response_text,
                    "error": str(e)
                })
        return results

    def extract_masked_entities(self, text: str) -> Dict[str, list]:
        """从文本中提取所有占位符实体

        用于检查是否还有未映射的内容
        """
        patterns = {
            "person": r'\[(项目经理|安全员|技术负责人|负责人|班组长|施工员|质检员|人员)[ABCDEFGHIJ]\]',
            "entity": r'\[(\d+号)(特大桥|隧道|涵洞|河流|立交)\]',
            "company": r'\[(建设单位|总承包单位|监理单位|设计单位|劳务分包单位|数字化实施方|某工程项目)\]',
            "coordinate": r'K\d+\+\d{3}',
            "masked": r'\[(手机号|证件号|邮箱|金额|单价|数量|桩号|合同编号|信用代码)脱敏\]',
        }

        result = {}
        for entity_type, pattern in patterns.items():
            matches = re.findall(pattern, text)
            if matches:
                result[entity_type] = matches

        return result
