#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
三级分类内容时效性审查模块

功能：从三级分类详情的content字段中提取规范引用，并进行时效性审查。
主要用于检测文本内容中引用的规范是否过时（如JTG B01-2011应更新为JTG B01-2014）。
"""

import re
import json
import asyncio
from typing import Any, Dict, List, Optional, Tuple
from dataclasses import dataclass, field
from functools import partial

from foundation.observability.logger.loggering import review_logger as logger
# [已注释] 旧的向量搜索和LLM判断相关导入
# from core.construction_review.component.reviewers.utils.reference_matcher import match_reference_files
# from core.construction_review.component.reviewers.utils.timeliness_determiner import determine_timeliness_issue
# from core.construction_review.component.reviewers.timeliness_basis_reviewer import BasisSearchEngine, StandardizedResponseProcessor

# [新增] 新的标准时效性审查模块
from core.construction_review.component.reviewers.standard_timeliness_reviewer import (
    StandardTimelinessReviewer,
)


@dataclass
class StandardReference:
    """规范引用数据类"""
    original_text: str           # 原始文本，如"《公路工程技术标准》（JTG B01-2011）"
    name: str                    # 规范名称，如"公路工程技术标准"
    number: str                  # 规范编号，如"JTG B01-2011"
    context: str                 # 上下文内容
    location_info: Dict[str, Any] = field(default_factory=dict)  # 位置信息


@dataclass
class ContentTimelinessResult:
    """内容时效性审查结果（保留用于兼容，新逻辑中不再直接使用）"""
    reference: StandardReference
    has_issue: bool
    issue_type: str              # 问题类型
    suggestion: str
    reason: str
    risk_level: str              # 风险等级（与原有逻辑一致：无风险/高风险）


class StandardExtractor:
    """规范引用提取器"""

    # 规范编号正则模式（匹配类似 GB 50010-2010、JTG B01-2014、GB/T 50502-2020 等格式）
    STANDARD_NUMBER_PATTERNS = [
        # 中国国家标准：GB 50010-2010、GB/T 50502-2020、GB 51-2001
        r'GB(?:/T)?\s*\d{1,5}(?:\.\d+)?\s*-\s*\d{4}',
        # 中国行业标准：JTG B01-2014、JTG D60-2015、JTG/T 3650-2020
        r'[A-Z]{2,3}(?:/T)?\s*[A-Z]?\s*\d{1,5}(?:\.\d+)?\s*-\s*\d{4}',
        # 地方标准：DB11/T 1234-2020
        r'DB\d{2}(?:/T)?\s*\d{1,5}\s*-\s*\d{4}',
        # 团体标准：T/CECS 123-2020
        r'T/\w+\s*\d{1,5}\s*-\s*\d{4}',
    ]

    # 规范名称与编号组合的正则模式
    STANDARD_FULL_PATTERN = re.compile(
        r'《([^《》]+)》\s*[（(]([^)）]+)[）)]',
        re.MULTILINE
    )

    # 仅规范编号模式
    STANDARD_NUMBER_ONLY_PATTERN = re.compile(
        r'(' + '|'.join(STANDARD_NUMBER_PATTERNS) + r')',
        re.MULTILINE | re.IGNORECASE
    )

    def __init__(self):
        self.extracted_cache: Dict[str, List[StandardReference]] = {}

    def extract_from_content(self, content: str, location_info: Optional[Dict] = None) -> List[StandardReference]:
        """
        从内容文本中提取规范引用

        Args:
            content: 内容文本（包含行号标记如 <80>）
            location_info: 位置信息（如三级分类代码、行号范围等）

        Returns:
            List[StandardReference]: 提取的规范引用列表
        """
        if not content:
            return []

        # 使用缓存
        cache_key = hash(content)
        if cache_key in self.extracted_cache:
            return self.extracted_cache[cache_key]

        references = []

        # 1. 提取完整格式：《名称》（编号）
        full_matches = self.STANDARD_FULL_PATTERN.findall(content)
        for name, number in full_matches:
            # 验证编号是否符合规范格式
            if self._is_valid_standard_number(number):
                original = f"《{name}》（{number}）"
                # 查找该引用在原文中的位置
                context = self._extract_context(content, original)
                ref = StandardReference(
                    original_text=original,
                    name=name.strip(),
                    number=number.strip(),
                    context=context,
                    location_info=location_info or {}
                )
                references.append(ref)

        # 2. 提取孤立的规范编号（用于补充）
        number_matches = self.STANDARD_NUMBER_ONLY_PATTERN.findall(content)
        for match in number_matches:
            number = match if isinstance(match, str) else match[0]
            # 检查是否已包含在完整格式中
            if not any(number in ref.number for ref in references):
                # 尝试提取该编号附近的上下文作为名称
                name = self._infer_name_from_context(content, number)
                original = f"《{name}》（{number}）" if name else number
                ref = StandardReference(
                    original_text=original,
                    name=name or "",
                    number=number.strip(),
                    context=self._extract_context(content, number),
                    location_info=location_info or {}
                )
                references.append(ref)

        # 去重（基于original_text）
        seen = set()
        unique_refs = []
        for ref in references:
            if ref.original_text not in seen:
                seen.add(ref.original_text)
                unique_refs.append(ref)

        self.extracted_cache[cache_key] = unique_refs
        return unique_refs

    def _is_valid_standard_number(self, number: str) -> bool:
        """验证是否为有效的规范编号"""
        number = number.strip().upper()
        # 检查是否匹配任一规范编号模式
        for pattern in self.STANDARD_NUMBER_PATTERNS:
            if re.match(pattern, number, re.IGNORECASE):
                return True
        return False

    def _extract_context(self, content: str, target: str, window: int = 50) -> str:
        """提取目标文本的上下文"""
        idx = content.find(target)
        if idx == -1:
            return ""
        start = max(0, idx - window)
        end = min(len(content), idx + len(target) + window)
        return content[start:end].strip()

    def _infer_name_from_context(self, content: str, number: str) -> str:
        """从上下文推断规范名称"""
        # 查找编号附近的《名称》格式
        pattern = re.compile(r'《([^《》]{3,50})》[^《》]{0,30}' + re.escape(number))
        match = pattern.search(content)
        if match:
            return match.group(1)
        return ""


class ContentTimelinessReviewer:
    """三级分类内容时效性审查器"""

    def __init__(self, max_concurrent: int = 4, db_pool=None):
        self.extractor = StandardExtractor()
        # [已注释] 旧的向量搜索引擎
        # self.search_engine = BasisSearchEngine()
        # self.response_processor = StandardizedResponseProcessor()
        self.max_concurrent = max_concurrent
        self._semaphore = None
        self.db_pool = db_pool
        self._timeliness_reviewer = None

    async def __aenter__(self):
        """异步上下文管理器入口"""
        if self._semaphore is None:
            self._semaphore = asyncio.Semaphore(self.max_concurrent)
        # [新增] 初始化新的时效性审查器
        if self._timeliness_reviewer is None:
            self._timeliness_reviewer = StandardTimelinessReviewer(db_pool=self.db_pool)
            if not self._timeliness_reviewer._service or not self._timeliness_reviewer._service._initialized:
                await self._timeliness_reviewer.__aenter__()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        # [新增] 关闭时效性审查器
        if self._timeliness_reviewer:
            await self._timeliness_reviewer.__aexit__(exc_type, exc_val, exc_tb)
        return False

    async def review_tertiary_content(
        self,
        tertiary_details: List[Dict[str, Any]],
        collection_name: str = "first_bfp_collection_status",
        progress_manager=None,
        callback_task_id: str = None
    ) -> List[Dict[str, Any]]:
        """
        审查三级分类内容中的规范时效性

        Args:
            tertiary_details: 三级分类详情列表，每项包含content字段
            collection_name: Milvus集合名称
            progress_manager: 进度管理器（可选，用于SSE推送）
            callback_task_id: 回调任务ID（可选）

        Returns:
            List[Dict]: 标准化的审查结果列表
        """
        if not tertiary_details:
            return []

        # 1. 从所有三级分类内容中提取规范引用
        all_references = []
        reference_to_location = {}  # 用于追踪引用来源

        for detail in tertiary_details:
            content = detail.get("content", "")
            if not content:
                continue

            location_info = {
                "third_category_name": detail.get("third_category_name", ""),
                "third_category_code": detail.get("third_category_code", ""),
                "start_line": detail.get("start_line", 0),
                "end_line": detail.get("end_line", 0),
            }

            refs = self.extractor.extract_from_content(content, location_info)
            for ref in refs:
                all_references.append(ref)
                # 记录引用来源（用于后续结果关联）
                if ref.original_text not in reference_to_location:
                    reference_to_location[ref.original_text] = []
                reference_to_location[ref.original_text].append(location_info)

        if not all_references:
            logger.info("未从三级分类内容中提取到规范引用")
            return []

        logger.info(f"从三级分类内容中提取到 {len(all_references)} 个规范引用")

        # 2. 对提取的规范进行时效性审查
        all_issues = []

        # [新增] 构建标准列表用于规则匹配
        standards_list = []
        for ref in all_references:
            standards_list.append({
                "standard_name": ref.name,
                "standard_number": ref.number
            })

        if not standards_list:
            logger.info("未提取到有效标准信息")
            return []

        # [新增] 使用新的时效性审查逻辑
        if not self._timeliness_reviewer:
            raise RuntimeError("时效性审查器未初始化，请使用异步上下文管理器")

        try:
            async with self._semaphore:
                # 执行规则匹配审查
                review_results = self._timeliness_reviewer.review_standards(standards_list)

                # 转换为标准格式
                standardized_results = self._timeliness_reviewer.convert_to_standardized_format(
                    review_results,
                    check_item="content_timeliness_check",
                    chapter_code="content",
                    check_item_code="content_timeliness_check"
                )

                # 增强结果：添加位置信息
                for item in standardized_results:
                    # 构建原始引用文本（《名称》（编号））
                    std_name = item.get("check_result", {}).get("standard_name", "")
                    std_number = item.get("check_result", {}).get("standard_number", "")
                    review_item_text = f"《{std_name}》（{std_number}）"

                    if review_item_text in reference_to_location:
                        locations = reference_to_location[review_item_text]
                        # 添加位置信息到结果
                        item["location_info"] = locations
                        # 添加三级分类上下文
                        contexts = []
                        for loc in locations:
                            ctx = f"[{loc.get('third_category_name', '')}] 第{loc.get('start_line', 0)}-{loc.get('end_line', 0)}行"
                            contexts.append(ctx)
                        item["content_context"] = "; ".join(contexts)

                        # 更新location字段为更详细的描述
                        if contexts:
                            item["check_result"]["location"] = f"{review_item_text}（出现在：{item['content_context']}）"

                all_issues.extend(standardized_results)

                # 统计结果
                issue_count = sum(1 for item in standardized_results if item.get("exist_issue", False))
                logger.info(f"内容时效性审查完成：总计 {len(standards_list)} 项引用，发现问题 {issue_count} 项")

                # SSE推送（如果提供了progress_manager）
                if progress_manager and callback_task_id:
                    try:
                        await progress_manager.update_stage_progress(
                            callback_task_id=callback_task_id,
                            stage_name="内容时效性审查",
                            status="processing",
                            message=f"完成内容时效性审查，{len(standards_list)}项，发现问题{issue_count}项",
                            overall_task_status="processing",
                            event_type="processing",
                            issues=standardized_results
                        )
                    except Exception as e:
                        logger.error(f"SSE推送失败: {e}")

        except Exception as e:
            logger.error(f"时效性审查处理失败: {e}")
            error_result = {
                "check_item": "content_timeliness_check",
                "chapter_code": "content",
                "check_item_code": "content_timeliness_check",
                "check_result": {"error": str(e)},
                "exist_issue": True,
                "risk_info": {"risk_level": "medium"}
            }
            all_issues.append(error_result)

        return all_issues

        # [已注释] 旧的向量搜索+LLM判断逻辑
        """
        # 分批处理（每批3个）
        batch_size = 3
        ref_texts = [ref.original_text for ref in all_references]
        total_batches = (len(ref_texts) + batch_size - 1) // batch_size

        for i in range(0, len(ref_texts), batch_size):
            batch_refs = all_references[i:i + batch_size]
            batch_texts = [ref.original_text for ref in batch_refs]
            batch_num = i // batch_size + 1

            try:
                async with self._semaphore:
                    # 搜索参考规范
                    search_tasks = []
                    for ref in batch_refs:
                        task = asyncio.create_task(
                            self._async_search_standard(ref.number, collection_name)
                        )
                        search_tasks.append(task)

                    search_results = await asyncio.gather(*search_tasks, return_exceptions=True)
                    ...  # 其余旧逻辑已省略
            except Exception as e:
                logger.error(f"批次 {batch_num} 处理失败: {e}")
        ...
        """

    # [已注释] 旧的向量搜索方法，已被新的规则匹配替代
    """
    async def _async_search_standard(
        self,
        standard_number: str,
        collection_name: str,
        top_k: int = 10
    ) -> List[dict]:
        '''异步搜索单个规范'''
        try:
            loop = asyncio.get_running_loop()
            func = partial(
                self.search_engine.hybrid_search,
                collection_name=collection_name,
                query_text=standard_number,
                top_k=top_k,
                ranker_type="weighted",
                dense_weight=0.3,
                sparse_weight=0.7
            )
            retrieved = await loop.run_in_executor(None, func)
            logger.debug(f"搜索 '{standard_number}' -> 找到 {len(retrieved or [])} 个结果")
            return retrieved or []
        except Exception as e:
            logger.error(f"搜索失败 '{standard_number}': {e}")
            return []
    """


# ===== 便捷函数 =====

async def review_tertiary_content_timeliness(
    tertiary_details: List[Dict[str, Any]],
    collection_name: str = "first_bfp_collection_status",  # [保留参数但不再使用]
    max_concurrent: int = 4,
    progress_manager=None,
    callback_task_id: str = None,
    db_pool=None  # [新增] 数据库连接池
) -> List[Dict[str, Any]]:
    """
    [已修改] 审查三级分类内容时效性的便捷函数

    Args:
        tertiary_details: 三级分类详情列表
        collection_name: Milvus集合名称（已废弃，保留参数用于兼容）
        max_concurrent: 最大并发数
        progress_manager: 进度管理器（可选）
        callback_task_id: 回调任务ID（可选）
        db_pool: 数据库连接池（用于新的规则匹配）

    Returns:
        List[Dict]: 标准化的审查结果列表
    """
    async with ContentTimelinessReviewer(max_concurrent=max_concurrent, db_pool=db_pool) as reviewer:
        return await reviewer.review_tertiary_content(
            tertiary_details=tertiary_details,
            collection_name=collection_name,
            progress_manager=progress_manager,
            callback_task_id=callback_task_id
        )


# ===== 测试代码 =====
if __name__ == "__main__":
    # 测试数据
    test_tertiary_details = [
        {
            "third_category_name": "国家方针、政策、标准和设计文件",
            "third_category_code": "NationalPoliciesStandardsAndDesignDocument",
            "start_line": 80,
            "end_line": 82,
            "content": "<80> 国家方针、政策、标准和设计文件\n<81> 《公路工程技术标准》（JTG B01-2011）\n<82> 《公路桥涵设计通用规范》（JTG D60-2015）"
        },
        {
            "third_category_name": "施工技术标准",
            "third_category_code": "ConstructionTechnicalStandards",
            "start_line": 100,
            "end_line": 102,
            "content": "<100> 施工技术标准\n<101> 《公路桥涵施工技术规范》（JTG/T 3650-2020）\n<102> 《混凝土结构设计规范》（GB 50010-2010）"
        }
    ]

    print(f"测试 {len(test_tertiary_details)} 个三级分类内容...")

    # 测试提取器
    extractor = StandardExtractor()
    for detail in test_tertiary_details:
        refs = extractor.extract_from_content(detail["content"])
        print(f"\n从 '{detail['third_category_name']}' 提取到 {len(refs)} 个规范引用:")
        for ref in refs:
            print(f"  - {ref.original_text}")

    # 测试完整审查流程（需要Milvus连接）
    # result = asyncio.run(review_tertiary_content_timeliness(test_tertiary_details))
    # print("\n审查结果:")
    # print(json.dumps(result, ensure_ascii=False, indent=2))
