#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
@Project   : lq-agent-api
@File      : ai_review_workflow.py
@IDE       : VsCode
@Author    :
@Date      : 2025-12-01 11:53:02

=================================

📋 方法总览 (Method Overview)

🏗️ 工作流核心方法:
├── _build_workflow()               # 构建LangGraph工作流图
├── execute()                       # 执行AI审查工作流
├── _start_node()                   # 开始节点
├── _initialize_progress_node()     # 初始化进度节点
├── _ai_review_node()               # AI审查核心节点
├── _complete_node()                # 完成节点
└── _error_handler_node()           # 错误处理节点

🔍 审查处理方法:
├── _filter_review_units()          # 筛选审查单元
├── _calculate_overall_risk()       # 计算总体风险等级
├── _aggregate_results()            # 汇总审查结果
├── _format_review_results_to_issues() # 格式化审查结果为问题列表
└── _parse_ai_review_response()     # 解析AI审查响应

🛠️ 工具辅助方法:
├── _check_ai_review_result()       # 检查AI审查结果
├── _get_workflow_graph()           # 获取工作流图(可视化)
└── _get_status()                   # 获取工作流状态

⚙️ 配置管理:
├── __init__()                      # 初始化工作流(支持审查模式配置)
└── set_review_location_label()     # 设置审查位置标签
'''

import asyncio
import json
import random
import re
from dataclasses import dataclass, asdict
from typing import Optional, Callable, Dict, Any, TypedDict, Annotated, List
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
from foundation.logger.loggering import server_logger as logger
from foundation.base.redis_connection import RedisConnectionFactory
from ..component import AIReviewEngine

# 常量定义
DEFAULT_SLICE_START_INDEX = 30
MAX_PROGRESS_PERCENTAGE = 100
RISK_LEVELS = {"high": "高风险", "medium": "中风险", "low": "低风险"}
DEFAULT_RISK_LEVEL = "medium"
REVIEW_TIMEOUT = 300  # 单个审查单元超时时间（秒）
WORKFLOW_TIMEOUT = 1800  # 整个工作流超时时间（秒，30分钟）


@dataclass
class ReviewResult:
    """审查结果"""
    unit_index: int
    unit_content: Dict[str, Any]
    basic_compliance: Dict[str, Any]
    technical_compliance: Dict[str, Any]
    rag_enhanced: Dict[str, Any]
    overall_risk: str

class AIReviewState(TypedDict):
    """AI审查工作流状态"""

    file_id: str
    callback_task_id: str
    user_id: str
    structured_content: Dict[str, Any]
    review_results: Optional[Dict[str, Any]]
    current_stage: str
    status: str
    error_message: Optional[str]
    progress_manager: Optional[Any]
    # 消息日志（用于LangGraph状态追踪）
    messages: Annotated[List[BaseMessage], add_messages]



class AIReviewWorkflow:
    """基于LangGraph的AI审查工作流"""

    def __init__(self, file_id: str, callback_task_id: str, user_id: str,
                 structured_content: Dict[str, Any], progress_manager=None,
                 max_review_units: int = None, review_mode: str = "all"):
        """
        初始化AI审查工作流

        Args:
            file_id: 文件ID
            callback_task_id: 回调任务ID
            user_id: 用户ID
            structured_content: 结构化内容
            progress_manager: 进度管理器
            max_review_units: 最大审查单元数量（None表示审查所有）
            review_mode: 审查模式 ("all"=全部, "first"=前N个, "random"=随机N个)
        """
        self.file_id = file_id
        self.callback_task_id = callback_task_id
        self.user_id = user_id
        self.structured_content = structured_content
        self.progress_manager = progress_manager
        self.ai_review_engine = AIReviewEngine()

        # 初始化核心功能和工具类
        self.core_fun = AIReviewCoreFun(self.ai_review_engine, max_review_units, review_mode)
        self.inter_tool = InterTool()

        self.max_review_units = max_review_units
        self.review_mode = review_mode
        self.graph = self._build_workflow()


    def _build_workflow(self) -> StateGraph:
        """
        构建AI审查的LangGraph工作流图

        Returns:
            StateGraph: 配置完成的LangGraph工作流图实例

        Note:
            创建包含开始、初始化进度、AI审查、完成和错误处理节点的完整工作流
            设置节点间的转换关系和条件边，支持错误处理流程
        """
        workflow = StateGraph(AIReviewState)
        workflow.add_node("start", self._start_node)
        workflow.add_node("initialize_progress", self._initialize_progress_node)
        workflow.add_node("ai_review", self._ai_review_node)
        workflow.add_node("complete", self._complete_node)
        workflow.add_node("error_handler", self._error_handler_node)
        workflow.set_entry_point("start")
        workflow.add_edge("start", "initialize_progress")
        workflow.add_edge("initialize_progress", "ai_review")
        workflow.add_edge("ai_review", "complete")
        workflow.add_edge("complete", END)
        workflow.add_edge("error_handler", END)

        # 添加条件边（错误处理）
        workflow.add_conditional_edges(
            "ai_review",
            self.inter_tool._check_ai_review_result,
            {
                "success": "complete",
                "error": "error_handler"
            }
        )

        self.graph = workflow.compile()
        self._get_workflow_graph()

        return self.graph

    async def execute(self) -> dict:
        """执行基于LangGraph的AI审查工作流"""
        try:
            logger.info(f"开始AI审查工作流，文件ID: {self.file_id}")
            initial_state = AIReviewState(
                file_id=self.file_id,
                callback_task_id=self.callback_task_id,
                user_id=self.user_id,
                structured_content=self.structured_content,
                review_results=None,
                current_stage="start",
                status="processing",
                error_message=None,
                progress_manager=self.progress_manager,
                messages=[HumanMessage(content=f"开始AI审查: {self.file_id}")]
            )

            # 执行LangGraph工作流，添加超时控制
            result = await asyncio.wait_for(
                self.graph.ainvoke(initial_state),
                timeout=WORKFLOW_TIMEOUT
            )

            logger.info(f"LangGraph AI审查工作流完成，文件ID: {self.file_id}")
            review_results = {
                'file_id': result['file_id'],
                'total_units': result['review_results'].get('total_units', 0) if result['review_results'] else 0,
                'successful_units': result['review_results'].get('successful_units', 0) if result['review_results'] else 0,
                'failed_units': result['review_results'].get('failed_units', 0) if result['review_results'] else 0,
                'review_results': result['review_results'].get('review_results', []) if result['review_results'] else [],
                'summary': result['review_results'].get('summary', {}) if result['review_results'] else {},
                'status': result['status']
            }

            logger.info(f"保存审查结果")
            # with open('temp/AI审查结果.json', "w",encoding='utf-8') as f:
            #     json.dump(result, f, ensure_ascii=False, indent=2, default=str)

            return review_results

        except asyncio.TimeoutError:
            logger.error(f"AI审查工作流超时（{WORKFLOW_TIMEOUT}秒），文件ID: {self.file_id}")
            raise TimeoutError(f"AI审查工作流执行超时，请检查文件大小或网络连接")
        except Exception as e:
            logger.error(f"LangGraph AI审查工作流执行失败: {str(e)}")
            raise

    async def _start_node(self, state: AIReviewState) -> AIReviewState:
        """开始节点"""
        logger.info(f"AI审查工作流正在启动...: {state['file_id']}")

        state["current_stage"] = "start"
        state["status"] = "processing"
        state["messages"].append(AIMessage(content=""))

        return state

    async def _initialize_progress_node(self, state: AIReviewState) -> AIReviewState:
        """初始化进度节点"""
        logger.info(f"初始化AI审查进度: {state['file_id']}")

        state["current_stage"] = "initialize_progress"

        # 更新进度
        if state["progress_manager"]:
            logger.debug(f"AI审查工作流中ProgressManager ID: {id(state['progress_manager'])}")
            logger.debug(f"AI审查工作流中ProgressManager有SSE回调: {hasattr(state['progress_manager'], 'sse_callback')}")
            await state["progress_manager"].update_stage_progress(
                callback_task_id=state["callback_task_id"],
                stage_name="AI审查",
                current=0,
                status="processing",
                message="开始AI审查",
                event_type="processing"
            )
        else:
            logger.warning(f"AI审查工作流中未找到ProgressManager: {state.get('progress_manager', 'None')}")

        state["messages"].append(AIMessage(content="进度初始化完成"))

        return state
    
    async def _ai_review_node(self, state: AIReviewState) -> AIReviewState:
        """
        AI审查节点

        Args:
            state: AI审查状态

        Returns:
            AIReviewState: 更新后的审查状态
        """
        try:
            state["current_stage"] = "ai_review"
            logger.info(f"AI审查节点开始执行，任务ID: {state['callback_task_id']}")

            # 1. 准备审查单元数据
            review_chunks, total_units, total_all_units = await self.core_fun._prepare_review_units(state)
            logger.info(f"准备审查单元完成，总单元数: {total_units}, 实际审查: {len(review_chunks)}")

            if not review_chunks:
                logger.warning(f"没有可审查的单元，任务ID: {state['callback_task_id']}")
                state["error_message"] = "没有可审查的单元"
                return state

            # 2. 发送开始审查进度
            await self.core_fun._send_start_review_progress(state, total_units)

            # 3. 执行并发审查
            logger.info(f"开始执行并发审查，任务ID: {state['callback_task_id']}")
            successful_results = await self.core_fun._execute_concurrent_reviews(review_chunks, total_units, state)
            logger.info(f"并发审查完成，成功结果: {len(successful_results)}, 任务ID: {state['callback_task_id']}")

            # 4. 汇总结果
            summary = self.inter_tool._aggregate_results(successful_results)

            review_results = {
                'total_all_units': total_all_units,  # 原始总单元数
                'total_reviewed_units': total_units,  # 实际审查的单元数
                'successful_units': len(successful_results),
                'failed_units': total_units - len(successful_results),
                'review_mode': self.review_mode,
                'max_review_units': self.max_review_units,
                'review_results': successful_results,
                'summary': summary
            }

            state["review_results"] = review_results
            state["messages"].append(AIMessage(
                content=f"AI审查完成，共处理{total_units}个单元，成功{len(successful_results)}个"
            ))

            logger.info(f"AI审查节点执行成功，任务ID: {state['callback_task_id']}")
            return state

        except Exception as e:
            logger.error(f"AI审查节点执行失败，任务ID: {state['callback_task_id']}, 错误: {str(e)}", exc_info=True)
            state["error_message"] = str(e)
            state["messages"].append(AIMessage(content=f"AI审查失败: {str(e)}"))
            return state

    async def _complete_node(self, state: AIReviewState) -> AIReviewState:
        """
        完成节点 - 工作流结束处理

        Args:
            state: AI审查工作流状态

        Returns:
            AIReviewState: 更新后的工作流状态，标记为已完成

        Note:
            设置最终状态为completed，更新进度管理器的完成状态
            发送工作流完成的消息日志
        """
        logger.info(f"AI审查完成: {state['file_id']}")

        state["current_stage"] = "complete"
        state["status"] = "completed"

        # 更新完成状态
        if state["progress_manager"]:
            await state["progress_manager"].update_stage_progress(
                callback_task_id=state["callback_task_id"],
                stage_name="AI审查",
                current=90,
                status="processing",
                message="AI审查完成",
                overall_task_status="processing",
                event_type="processing"
            )

        state["messages"].append(AIMessage(content="AI审查工作流完成"))

        return state

    async def _error_handler_node(self, state: AIReviewState) -> AIReviewState:
        """
        错误处理节点 - 处理工作流中的异常情况

        Args:
            state: AI审查工作流状态，包含错误信息

        Returns:
            AIReviewState: 更新后的工作流状态，标记为失败

        Note:
            设置状态为failed，通过进度管理器发送错误通知
            记录详细的错误信息到日志中
        """
        logger.error(f"AI审查错误处理: {state['file_id']}, 错误: {state['error_message']}")

        state["status"] = "failed"
        state["current_stage"] = "error_handler"

        # 更新错误状态
        if state["progress_manager"]:
            await state["progress_manager"].update_stage_progress(
                callback_task_id=state["callback_task_id"],
                stage_name="AI审查",
                current=50,
                status="failed",
                message=f"AI审查失败: {state['error_message']}",
                overall_task_status="failed",
                event_type="error"
            )

        state["messages"].append(AIMessage(
            content=f"错误处理: {state['error_message']}"
        ))

        return state

    def _get_workflow_graph(self):
        """获取工作流图（可视化输出）"""
        grandalf_graph = self.graph.get_graph()
        grandalf_graph.print_ascii()
 
    async def _get_status(self) -> dict:
        """获取工作流状态"""
        if self.progress_manager:
            return await self.progress_manager.get_progress(self.callback_task_id)
        return {}


class AIReviewCoreFun:
    """AI审查核心功能类 - 负责具体的审查逻辑和数据处理"""

    def __init__(self, ai_review_engine, max_review_units: int = None, review_mode: str = "all"):
        """
        初始化AI审查核心功能类

        Args:
            ai_review_engine: AI审查引擎实例
            max_review_units: 最大审查单元数量（None表示审查所有）
            review_mode: 审查模式 ("all"=全部, "first"=前N个, "random"=随机N个)
        """
        self.ai_review_engine = ai_review_engine
        self.max_review_units = max_review_units
        self.review_mode = review_mode
        # 添加消息推送锁，确保事件顺序发送
        self.message_lock = asyncio.Lock()
        

    async def _execute_concurrent_reviews(self, review_chunks: List[Dict[str, Any]],
                                          total_units: int, state: AIReviewState) -> List[ReviewResult]:
        """
        执行并发审查

        Args:
            review_chunks: 审查单元列表
            total_units: 总单元数
            state: AI审查状态

        Returns:
            List[ReviewResult]: 审查结果列表
        """
        
        try:
            # 简化方案：并发执行，每个单元完成时立即推送消息
            semaphore = asyncio.Semaphore(3)  # 允许3个并发审查

            async def process_unit_and_notify(unit_index, unit_content):
                """处理单个单元，完成后立即推送通知"""
                async with semaphore:
                    # 执行单个单元审查
                    result = await self._review_single_unit(unit_content, unit_index, total_units, state)

                    # 审查完成后立即推送通知
                    if result.overall_risk != "error":
                        section_label = unit_content.get('section_label', f'第{unit_index + 1}部分')
                        logger.info(f"section_label:  {section_label}")
                        # 格式化issues以获取问题数量
                        issues = self._format_review_results_to_issues(
                            state["callback_task_id"],
                            unit_index,
                            f"第{unit_content.get('page', '')}页：{section_label}",
                            unit_content,
                            result.basic_compliance,
                            result.technical_compliance
                        )

                        current = int(((unit_index + 1) / total_units) * 100)

                        # 立即发送单元审查详情（包含unit_review和processing_flag事件）
                        await self._send_unit_review_progress(state, unit_index, total_units, section_label, issues, current)

                    else:
                        logger.error(f"执行单个单元审查失败: {str(result.error_message)}")
                    return result

            # 创建并发任务
            tasks = [
                asyncio.create_task(process_unit_and_notify(i, unit_content))
                for i, unit_content in enumerate(review_chunks)
            ]

            # 等待所有任务完成
            all_results = await asyncio.gather(*tasks)

            # 过滤成功结果
            successful_results = [result for result in all_results if result.overall_risk != "error"]
            return successful_results

        except Exception as e:
            logger.error(f"执行并发审查失败: {str(e)}")
            return []



    async def _prepare_review_units(self, state: AIReviewState) -> tuple:
        """准备审查单元数据 (增加清理旧进度缓存)"""
        try:
            # 筛选要审查的单元
            all_chunks = state['structured_content']['chunks']
            review_chunks = self._filter_review_units(all_chunks)

            total_units = len(review_chunks)
            total_all_units = len(all_chunks)

            # 【修复 3】: 任务开始前，清理 Redis 中的旧计数，防止进度条计算错误
            try:
                task_id = state.get("callback_task_id", "")
                if task_id:
                    redis_client = await RedisConnectionFactory.get_connection()
                    completed_key = f"ai_review:overall_task_progress:{task_id}:completed"
                    await redis_client.delete(completed_key)
                    logger.info(f"已清理旧进度缓存: {completed_key}")
            except Exception as e:
                logger.warning(f"清理进度缓存失败 (不影响主流程): {str(e)}")

            logger.info(f"AI审查开始: 总单元数 {total_all_units}, 实际审查 {total_units} 个单元")
            return review_chunks, total_units, total_all_units
        except Exception as e:
            logger.error(f"准备审查单元失败: {str(e)}")
            raise

    async def _review_single_unit(self, unit_content: Dict[str, Any], unit_index: int,
                                  total_units: int, state: AIReviewState) -> ReviewResult:
        """
        审查单个单元的核心业务逻辑

        Args:
            unit_content: 单元内容
            unit_index: 单元索引
            total_units: 总单元数
            state: AI审查状态

        Returns:
            ReviewResult: 单元审查结果
        """
        try:

            # 构建Trace ID
            trace_id_idx = f"({state['callback_task_id']}-{unit_index})"

            # 获取section_label用于stage_name
            section_label = unit_content.get('section_label', f'第{unit_index + 1}部分')
            page = unit_content.get('page', '')
            review_location_label = f"第{page}页：{section_label}"

            # 设置review_location_label到AIReviewEngine
            self.ai_review_engine.set_review_location_label(review_location_label)
            logger.info(f"review_location_label:  {review_location_label}")
            stage_name = f"AI审查:{section_label}"

            # 方法内部进度计算（基于当前处理的单元）
            current_progress = int((unit_index / total_units) * 100)

            # 构建进度消息
            #message = f"正在处理第 {unit_index + 1}/{total_units} 个单元: {section_label}"
            #logger.info(f"开始处理单元: {unit_index + 1}/{total_units} - {section_label}")

            # 并发执行各种原子化审查方法，添加超时控制
            review_tasks = [
                asyncio.wait_for(
                    self.ai_review_engine.basic_compliance_check(trace_id_idx, unit_content, stage_name, state, current_progress),
                    timeout=REVIEW_TIMEOUT
                ),
                asyncio.wait_for(
                    self.ai_review_engine.technical_compliance_check(trace_id_idx, unit_content, stage_name, state, current_progress),
                    timeout=REVIEW_TIMEOUT
                ),
            ]

            # 等待所有审查完成
            review_results = await asyncio.gather(*review_tasks, return_exceptions=True)
            # 处理异常结果
            basic_result = review_results[0] if not isinstance(review_results[0], Exception) else {"error": str(review_results[0])}
            technical_result = review_results[1] if len(review_results) > 1 and not isinstance(review_results[1], Exception) else {"error": str(review_results[1]) if len(review_results) > 1 else "No result"}

            # RAG检查已注释，提供空结果
            rag_result = {"error": "RAG check disabled"}

            # 计算总体风险等级
            inter_tool = InterTool()
            overall_risk = inter_tool._calculate_overall_risk(basic_result, technical_result, rag_result)

            # 格式化审查结果（注意：实际进度推送现在在 _execute_concurrent_reviews 中按顺序处理）
            # 这里保存格式化结果到ReviewResult中，供后续推送使用

            
            return ReviewResult(
                unit_index=unit_index,
                unit_content=unit_content,
                basic_compliance=basic_result,
                technical_compliance=technical_result,
                rag_enhanced=rag_result,
                overall_risk=overall_risk
            )

        except asyncio.TimeoutError:
            logger.error(f"审查单元 {unit_index} 超时")
            return ReviewResult(
                unit_index=unit_index,
                unit_content=unit_content,
                basic_compliance={"error": f"审查超时（{REVIEW_TIMEOUT}秒）"},
                technical_compliance={"error": f"审查超时（{REVIEW_TIMEOUT}秒）"},
                rag_enhanced={"error": f"审查超时（{REVIEW_TIMEOUT}秒）"},
                overall_risk="error"
            )
        except Exception as e:
            logger.error(f"审查单元 {unit_index} 失败: {str(e)}")
            return ReviewResult(
                unit_index=unit_index,
                unit_content=unit_content,
                basic_compliance={"error": str(e)},
                technical_compliance={"error": str(e)},
                rag_enhanced={"error": str(e)},
                overall_risk="error"
            )

    async def _send_start_review_progress(self, state: AIReviewState, total_units: int) -> None:
        """
        发送开始审查的进度更新

        Args:
            state: AI审查状态
            total_units: 总审查单元数
        """
        try:
            if state["progress_manager"]:
                await state["progress_manager"].update_stage_progress(
                    callback_task_id=state["callback_task_id"],
                    stage_name="AI审查",
                    current=0,
                    status="processing",
                    message=f"开始AI审查，共 {total_units} 个审查单元",
                    event_type="processing"
                )
        except Exception as e:
            logger.warning(f"发送开始进度更新失败: {str(e)}")

    async def _send_unit_review_progress(self, state: AIReviewState, unit_index: int,
                                            total_units: int, section_label: str,
                                            issues: List[Dict], current: int) -> None:
        """
        发送单元审查详细信息 - 强制串行并统一进度值
        """
        async with self.message_lock:
            try:
                # 1. 计算问题数量
                issues_count = 0
                if isinstance(issues, list) and issues:
                    issues_count = sum(
                        1 for issue in issues
                        for issue_data in issue.values()
                        for review_item in issue_data.get("review_lists", [])
                        if review_item.get("exist_issue", False)
                    )

                # 2. 发送全局进度 (Processing Flag)
                # 【修复 1】: 获取 Redis 计算出的真实进度 (real_current)
                # 即使这里传入了 current (基于 index)，我们优先使用 Redis 返回的真实完成度
                real_current = await self._send_unit_overall_progress(
                    state, unit_index, total_units, section_label, issues_count
                )
                
                # 如果 Redis 失败返回 None，则回退使用传入的 current
                final_current = real_current if real_current is not None else current

                # 【修复 2】: 强制休眠 50ms。
                # 这解决了 "Client didn't synchronously receive" 的问题。
                # 它迫使网络缓冲区刷新，并给前端 UI 渲染循环留出时间处理上一个 Flag 事件。
                await asyncio.sleep(0.05)

                # 3. 发送单元详情 (Unit Review)
                if isinstance(issues, list) and issues and state["progress_manager"]:
                    stage_name = f"AI审查:{section_label}"

                    await state["progress_manager"].update_stage_progress(
                        callback_task_id=state["callback_task_id"],
                        stage_name=stage_name,
                        current=final_current,  # 【关键】使用与 Flag 事件完全一致的进度值
                        status="unit_review_update",
                        message=f"发现{issues_count}个问题: {section_label}",
                        issues=issues,
                        user_id=state.get("user_id", ""),
                        overall_task_status="processing",
                        event_type="unit_review"
                    )

                    # 再次微小延迟，确保 Clear 不会吞掉 Review
                    await asyncio.sleep(0.02)

                    # 清空当前issues
                    await state["progress_manager"].update_stage_progress(
                        callback_task_id=state["callback_task_id"],
                        issues=['clear']
                    )

            except Exception as e:
                logger.warning(f"发送单元审查详情失败: {str(e)}")

    async def _send_unit_overall_progress(self, state: AIReviewState, unit_index: int,
                                           total_units: int, section_label: str,
                                           issues_count: int = None) -> Optional[int]:
        """
        发送单元完成进度更新 - 返回计算出的实时进度
        Returns:
            int: 基于 Redis 统计的实时进度百分比
        """
        current_percent = None
        try:
            task_id = state.get("callback_task_id", "")
            redis_client = None
            try:
                redis_client = await RedisConnectionFactory.get_connection()
            except Exception as e:
                logger.warning(f"Redis连接失败: {str(e)}")

            completed_count = 0
            
            if redis_client and task_id:
                completed_key = f"ai_review:overall_task_progress:{task_id}:completed"
                # 原子操作
                await redis_client.sadd(completed_key, str(unit_index))
                await redis_client.expire(completed_key, 3600)
                completed_count = await redis_client.scard(completed_key)
                
                # 计算进度
                current_percent = int((completed_count / total_units) * 100)
            else:
                # 降级方案
                completed_count = unit_index + 1
                current_percent = int((completed_count / total_units) * 100)

            # 构建消息
            if issues_count is not None and issues_count > 0:
                message = f"已完成第 {completed_count}/{total_units} 个单元: {section_label}（已发现{issues_count}个问题）"
            else:
                message = f"已完成第 {completed_count}/{total_units} 个单元: {section_label}"

            logger.info(f"进度更新: {current_percent}% - {message}")

            if state["progress_manager"]:
                await state["progress_manager"].update_stage_progress(
                    callback_task_id=state["callback_task_id"],
                    stage_name="AI审查",
                    current=current_percent,
                    status="processing",
                    message=message,
                    user_id=state.get("user_id", ""),
                    overall_task_status="processing",
                    event_type="processing_flag"
                )
            
            return current_percent

        except Exception as e:
            logger.warning(f"发送单元完成进度更新失败: {str(e)}")
            # 发生异常时，尝试返回一个基于 index 的估算值
            try:
                return int(((unit_index + 1) / total_units) * 100)
            except:
                return 0

    def _format_review_results_to_issues(self,callback_task_id: str, unit_index: int, review_location_label: str,
                                        unit_content: Dict[str, Any], basic_result: Dict[str, Any],
                                        technical_result: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        将审查结果格式化为issues结构

        Args:
            callback_task_id: 回调任务ID，用于生成唯一issue_id
            unit_index: 单元索引，用于生成唯一issue_id
            review_location_label: 审查位置标签，如"第3页：第一章"
            unit_content: 单元内容，包含原始文本等信息
            basic_result: 基础合规性审查结果，包含各项检查结果
            technical_result: 技术性审查结果，包含技术标准检查结果

        Returns:
            List[Dict]: 格式化后的issues列表，每个issue包含：
                - issue_id: 唯一标识符，格式为"{callback_task_id}-{risk_level}-{unit_index}"
                - metadata: 元数据，包含审查位置和原始内容
                - risk_summary: 风险摘要，包含最高风险等级和问题数量统计
                - review_lists: 详细审查问题列表

        Note:
            自动跳过overall_score字段，提取所有检查项的详细结果
            支持风险等级统计和最高风险等级确定
        """
        issues = []
        review_lists = []
        risk_count = {"high": 0, "medium": 0, "low": 0}
        max_risk_level = "low"

        # 合并所有审查结果
        all_results = {}
        if basic_result:
            all_results.update(basic_result)
        if technical_result:
            all_results.update(technical_result)

        logger.info(f"开始格式化审查结果，合并后结果: {list(all_results.keys())}")

        for check_key, check_result in all_results.items():
            logger.info(f"处理检查项: {check_key}, 结果类型: {type(check_result)}")

            if check_key == 'overall_score':  # 跳过分数字段
                logger.info(f"跳过分数字段: {check_key}")
                continue

            if check_result and "details" in check_result and "response" in check_result["details"]:
                response = check_result["details"]["response"]
                check_name = check_result["details"].get("name", check_key)
                logger.info(f"解析检查项 {check_name} 的响应，长度: {len(response)}")
                check_issues = self._parse_ai_review_response(response, check_name)
                review_lists.extend(check_issues)
            else:
                logger.warning(f"检查项 {check_key} 格式不符合要求，缺少details或response字段")
                logger.warning(f"check_result内容: {check_result}")

        # 统计风险等级
        for issue in review_lists:
            risk_level = issue.get("risk_info", {}).get("risk_level", "low")
            if risk_level in risk_count:
                risk_count[risk_level] += 1

        # 确定最高风险等级
        if risk_count["high"] > 0:
            max_risk_level = "high"
        elif risk_count["medium"] > 0:
            max_risk_level = "medium"

        # 如果有审查结果，创建issue
        if review_lists:
            issue_id = f"{callback_task_id}-{max_risk_level if max_risk_level else '0'}-{unit_index}"
            issue = {
                issue_id: {
                    "metadata": {
                        "review_location_label": review_location_label,
                        "original_content": unit_content.get('content', '')
                    },
                    "risk_summary": {
                        "max_risk_level": max_risk_level if max_risk_level else '0',
                        "risk_count": risk_count if risk_count else 0
                    },
                    "review_lists": review_lists
                }
            }
            issues.append(issue)

        return issues

    def _parse_ai_review_response(self,response: str, check_name: str) -> List[Dict[str, Any]]:
        """
        解析AI审查的JSON格式响应

        Args:
            response: AI审查响应内容
            check_name: 检查项名称（如"词句语法检查"）

        Returns:
            List[Dict]: 解析后的审查结果列表，包含check_item、check_result、exist_issue、risk_info等字段

        Note:
            支持识别"无明显问题"等关键词，自动设置风险等级
            解析新的英文键名JSON格式: issue_point, location, suggestion, reason, risk_level
        """
        review_lists = []

        try:
            if "无明显问题" in response or "无问题" in response or "符合要求" in response:
                review_lists.append({
                    "check_item": check_name,
                    "check_result": "无明显问题",
                    "exist_issue": False,
                    "risk_info": {"risk_level": "low"}
                })
                return review_lists

            # 尝试解析JSON格式响应

            # 首先检查响应是否直接被{}包裹
            response_stripped = response.strip()
            json_data = None

            if (response_stripped.startswith('{') and response_stripped.endswith('}')) or \
               (response_stripped.startswith('{\n') and response_stripped.endswith('\n}')):
                # 响应被{}包裹，直接解析
                try:
                    json_data = json.loads(response_stripped)
                except json.JSONDecodeError:
                    logger.warning(f"直接JSON解析失败，尝试查找JSON代码块")

            # 如果直接解析失败，查找JSON代码块
            if json_data is None:
                # 改进的正则表达式：正确处理多行JSON和转义字符
                json_pattern = r'```json\s*(\[[\s\S]*?\]|\{[\s\S]*?\})\s*```'
                json_matches = re.findall(json_pattern, response)

                # 如果改进的正则仍然匹配不到，使用更宽松的模式
                if not json_matches:
                    json_pattern = r'```json\s*(.*?)\s*```'
                    json_matches = re.findall(json_pattern, response, re.DOTALL)

            else:
                json_matches = [response_stripped]  # 使用整个响应作为JSON

            # 如果所有方法都失败，尝试最后的JSON提取策略
            if not json_matches:
                logger.warning("标准JSON提取失败，尝试智能JSON提取策略")

                # 策略1: 查找被JSON数组/对象包围的内容
                array_pattern = r'\[\s*\{.*?\}\s*\]'
                object_pattern = r'\{[^{}]*"issue_point"[^{}]*\}'

                array_matches = re.findall(array_pattern, response, re.DOTALL)
                if array_matches:
                    json_matches = array_matches
                    logger.info(f"数组模式匹配成功，找到 {len(array_matches)} 个JSON数组")
                else:
                    object_matches = re.findall(object_pattern, response, re.DOTALL)
                    if object_matches:
                        json_matches = object_matches
                        logger.info(f"对象模式匹配成功，找到 {len(object_matches)} 个JSON对象")

            # 最后的备选方案：查找包含关键JSON字段的内容
            if not json_matches:
                logger.warning("所有JSON提取策略失败，查找包含关键字段的内容")
                key_pattern = r'[^`]*["\']issue_point["\'][^`]*["\']location["\'][^`]*'
                key_matches = re.findall(key_pattern, response, re.DOTALL)
                if key_matches:
                    # 尝试将匹配内容包装为有效JSON
                    for match in key_matches:
                        # 简单包装，可能需要更复杂的逻辑
                        wrapped_match = f'[{match}]' if not match.strip().startswith('[') else match
                        json_matches.append(wrapped_match)
                    logger.info(f"关键字段模式匹配成功，生成 {len(json_matches)} 个JSON候选")

            if json_matches:
                logger.info(f"成功匹配到 {len(json_matches)} 个JSON代码块")
                # 解析找到的JSON
                for i, json_str in enumerate(json_matches):
                    try:
                        # 如果是直接解析的JSON，不需要重新解析
                        if json_str == response_stripped and json_data is not None:
                            issue_data = json_data
                            logger.debug(f"使用直接解析的JSON数据 (第{i+1}个)")
                        else:
                            # 清理JSON字符串
                            json_str = json_str.strip()
                            if not json_str:
                                logger.warning(f"第{i+1}个JSON代码块为空，跳过")
                                continue

                            logger.debug(f"尝试解析第{i+1}个JSON: {json_str[:100]}...")
                            # 解析JSON
                            issue_data = json.loads(json_str)
                            logger.info(f"第{i+1}个JSON解析成功，包含 {len(issue_data) if isinstance(issue_data, (list, dict)) else 0} 个元素")

                        risk_level = issue_data.get("risk_level", "")

                        # 确定风险等级
                        if not risk_level:
                            risk_level = "medium"  # 默认中等风险
                        else:
                            risk_level = risk_level.lower()
                            if "高" in risk_level or "high" in risk_level:
                                risk_level = "high"
                            elif "中" in risk_level or "medium" in risk_level:
                                risk_level = "medium"
                            else:
                                risk_level = "low"

                        # 直接存储JSON字段
                        review_lists.append({
                            "check_item": check_name,
                            "check_result": issue_data,  # 直接存储原始JSON数据
                            "exist_issue": True,
                            "risk_info": {"risk_level": risk_level}
                        })

                    except json.JSONDecodeError as je:
                        logger.warning(f"JSON解析失败: {str(je)}, JSON内容: {json_str[:100]}...")
                        # 如果JSON解析失败，回退到文本解析
                        continue

            # 如果没有成功解析到JSON，使用旧的文本解析方法
            if not review_lists:
                lines = response.split('\n')
                risk_level = "medium"  # 默认中等风险

                # 扫描提取风险等级（支持中英文）
                for line in lines:
                    line = line.strip()
                    if line.startswith('**风险等级**：') or line.startswith('**risk_level**：'):
                        if '：' in line:
                            extracted_risk = line.split('：', 1)[1].strip().lower()
                        elif ':' in line:
                            extracted_risk = line.split(':', 1)[1].strip().lower()

                        if "高" in extracted_risk or "high" in extracted_risk:
                            risk_level = "high"
                        elif "中" in extracted_risk or "medium" in extracted_risk:
                            risk_level = "medium"
                        else:
                            risk_level = "low"
                        break

                review_lists.append({
                    "check_item": check_name,
                    "check_result": response,  # 存储完整响应作为备选
                    "exist_issue": True,
                    "risk_info": {"risk_level": risk_level}
                })

        except Exception as e:
            logger.error(f"解析AI审查响应失败: {str(e)}")
            review_lists.append({
                "check_item": check_name,
                "check_result": response,
                "exist_issue": True,
                "risk_info": {"risk_level": "low"}
            })

        return review_lists

    def _filter_review_units(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        根据配置筛选要审查的单元

        Args:
            chunks: 所有审查单元

        Returns:
            List[Dict[str, Any]]: 筛选后的审查单元

        Note:
            使用预设的起始索引进行切片，确保不会跳过前面的重要内容
        """
        if self.max_review_units is None or self.review_mode == "all":
            return chunks

        # 验证原始chunks不为空
        if not chunks:
            logger.warning("没有可用的审查单元")
            return []

        # 安全的切片操作，考虑边界情况
        # 使用预设的起始索引进行切片，避免跳过前面的内容
        start_index = min(DEFAULT_SLICE_START_INDEX, len(chunks) - 1)  # 确保start_index不超过数组边界
        chunks = chunks[start_index:]

        # 再次验证切片后的结果
        if not chunks:
            logger.warning(f"从索引{start_index}切片后没有可用的审查单元")
            return []

        total_chunks = len(chunks)
        actual_review_count = min(self.max_review_units, total_chunks)

        logger.info(f"审查模式: {self.review_mode}, 总单元数: {total_chunks}, 实际审查数: {actual_review_count}")

        if self.review_mode == "first":
            # 取前N个
            return chunks[:actual_review_count]
        elif self.review_mode == "random":
            # 随机取N个
            return random.sample(chunks, actual_review_count)
        else:
            # 默认取前N个
            return chunks[:actual_review_count]


class InterTool:
    """AI审查工具类 - 负责辅助计算和结果处理"""

    def _calculate_overall_risk(self, basic_result: Dict, technical_result: Dict, rag_result: Dict) -> str:
        """
        计算总体风险等级

        Args:
            basic_result: 基础合规性审查结果，包含overall_score字段
            technical_result: 技术性审查结果，包含overall_score字段
            rag_result: RAG增强审查结果（当前未使用）

        Returns:
            str: 风险等级 ("low", "medium", "high")

        Note:
            风险等级计算逻辑：
            - low: 基础和技术审查都达到90分以上
            - medium: 基础和技术审查都达到70分以上
            - high: 其他情况
            异常情况下返回默认风险等级medium
        """
        try:
            # 基于各种审查结果计算风险等级
            # 风险等级计算逻辑：基础和技术审查都达到90分以上为低风险，70分以上为中风险，否则为高风险
            basic_score = basic_result.get('overall_score', 0)
            technical_score = technical_result.get('overall_score', 0)

            if basic_score >= 90 and technical_score >= 90:
                return "low"
            elif basic_score >= 70 and technical_score >= 70:
                return "medium"
            else:
                return "high"
        except (KeyError, TypeError, ValueError) as e:
            logger.warning(f"风险等级计算异常: {str(e)}，使用默认风险等级")
            return DEFAULT_RISK_LEVEL

    def _aggregate_results(self, successful_results: List[ReviewResult]) -> Dict[str, Any]:
        """
        汇总审查结果

        Args:
            successful_results: 成功的审查结果列表，每个结果包含风险等级和得分

        Returns:
            Dict[str, Any]: 汇总后的统计信息，包含以下字段：
                - risk_stats: 各风险等级的数量统计 {"low": 0, "medium": 0, "high": 0}
                - avg_basic_score: 基础合规性平均得分
                - avg_technical_score: 技术性审查平均得分
                - total_reviewed: 成功审查的总数量

        Note:
            当输入为空时返回空字典，异常时记录错误并返回空字典
        """
        try:
            if not successful_results:
                return {}

            # 计算风险等级统计
            risk_stats = {"low": 0, "medium": 0, "high": 0, "error": 0}
            for result in successful_results:
                risk_stats[result.overall_risk] += 1

            # 计算平均分
            total_basic_score = sum(r.basic_compliance.get('overall_score', 0) for r in successful_results)
            total_technical_score = sum(r.technical_compliance.get('overall_score', 0) for r in successful_results)

            avg_basic_score = total_basic_score / len(successful_results)
            avg_technical_score = total_technical_score / len(successful_results)

            return {
                'risk_stats': risk_stats,
                'avg_basic_score': avg_basic_score,
                'avg_technical_score': avg_technical_score,
                'total_reviewed': len(successful_results)
            }
        except (ZeroDivisionError, KeyError, TypeError) as e:
            logger.error(f"结果汇总失败: {str(e)}")
            return {}

    def _check_ai_review_result(self, state: AIReviewState) -> str:
        """
        检查AI审查结果状态

        Args:
            state: AI审查工作流状态

        Returns:
            str: 状态标识 ("success" 或 "error")

        Note:
            根据状态中是否存在错误信息来判断审查是否成功
        """
        if state.get("error_message"):
            return "error"
        return "success"

