#!/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_check_item()    # AI审查项检查节点（基于review_item_config）
├── _save_results_node()            # 保存结果节点（入库/本地文件）
├── _complete_node()                # 完成节点
├── _error_handler_node()           # 错误处理节点
└── _terminate_node()               # 终止节点

🛠️ 工作流辅助方法:
├── _should_check_item_or_dimensions() # 检查应该使用哪种审查配置
├── _should_terminate_or_error()    # 检查是否应该终止或发生错误
├── _get_workflow_graph()           # 获取工作流图(可视化)
├── _save_workflow_graph()          # 保存工作流图到temp文件夹
├── _get_status()                   # 获取工作流状态
└── _dummy_review_task()            # 空任务（方法不存在时使用）

'''

import asyncio
import json
import random
import re
from sre_parse import JUMP
import time
import os
from typing import Dict, Tuple, Union, List
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
import pandas as pd
from foundation.observability.logger.loggering import review_logger as logger
from foundation.observability.cachefiles import cache, CacheBaseDir
from core.construction_review.component.reviewers.utils.directory_extraction import (
    extract_basis_with_langchain_qwen,
)
from foundation.infrastructure.cache.redis_connection import RedisConnectionFactory
from ..component.ai_review_engine import AIReviewEngine
from ..component.reviewers.utils.inter_tool import InterTool
from core.base.task_models import TaskFileInfo
from .core_functions import AIReviewCoreFun
from .types import AIReviewState


# @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 AIReviewWorkflow:
    """基于LangGraph的AI审查工作流"""

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

        Args:
            task_file_info: TaskFileInfo 实例，包含所有任务相关信息
            structured_content: 结构化内容
            progress_manager: 进度管理器
            max_review_units: 最大审查单元数量（None表示审查所有）
            review_mode: 审查模式 ("all"=全部, "first"=前N个, "random"=随机N个)
            db_pool: 数据库连接池（用于时效性审查等新逻辑）
        """
        # 工作流超时时间定义
        self.WORKFLOW_TIMEOUT = 3600

        # 任务文件信息
        self.task_info = task_file_info

        self.file_id = task_file_info.file_id
        self.callback_task_id = task_file_info.callback_task_id
        self.user_id = task_file_info.user_id
        self.file_name = task_file_info.file_name

        # 其他属性
        self.structured_content = structured_content
        self.progress_manager = progress_manager

        # 传递 TaskFileInfo 实例和 db_pool
        self.ai_review_engine = AIReviewEngine(task_file_info, db_pool=db_pool)

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

        self.max_review_units = max_review_units
        self.max_concurrent = 20 # 规范性与时效性审查最大并发数
        self.review_mode = review_mode

        # 延迟导入 WorkflowManager（避免循环导入）
        from core.base.workflow_manager import WorkflowManager
        self.workflow_manager = WorkflowManager()

        self.graph = self._build_workflow()


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

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

        Note:
            创建包含开始、初始化进度、AI审查项检查、保存结果、完成、错误处理和终止节点的完整工作流
            设置节点间的转换关系和条件边，支持错误处理流程和任务终止流程
            工作流路径: start → initialize_progress → ai_review_check_item → save_results → complete → END
        """
        workflow = StateGraph(AIReviewState)
        workflow.add_node("start", self._start_node)
        workflow.add_node("initialize_progress", self._initialize_progress_node)
        workflow.add_node("ai_review_check_item",self._ai_review_node_check_item)
        workflow.add_node("save_results", self._save_results_node)  # 添加保存结果节点
        workflow.add_node("complete", self._complete_node)
        workflow.add_node("error_handler", self._error_handler_node)
        workflow.add_node("terminate", self._terminate_node)  # 终止节点

        workflow.set_entry_point("start")
        workflow.add_edge("start", "initialize_progress")
        # 添加条件边：根据配置类型选择不同的审查节点
        workflow.add_conditional_edges(
            "initialize_progress",
            self._should_check_item_or_dimensions,
            {
                "activate_ai_review_check_item": "ai_review_check_item",  # 使用 review_item_config
            }
        )

        # 添加条件边（错误处理 + 终止检查）
        workflow.add_conditional_edges(
            "ai_review_check_item",
            self._should_terminate_or_error,
            {
                "terminate": "terminate",  # 终止路径
                "success": "save_results",  # 成功后先保存结果
                "error": "error_handler"  # 错误处理
            }
        )

        # 添加保存结果到完成的边
        workflow.add_edge("save_results", "complete")
        workflow.add_edge("complete", END)
        workflow.add_edge("error_handler", END)
        workflow.add_edge("terminate", END)

        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=self.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"保存审查结果")
            # 只缓存可序列化的数据，移除 progress_manager, messages, task_file_info 等不可序列化对象
            cacheable_result = {
                'file_id': result['file_id'],
                'callback_task_id': result['callback_task_id'],
                'user_id': result['user_id'],
                'file_name': result.get('file_name', ''),
                'current_stage': result.get('current_stage', ''),
                'status': result['status'],
                'error_message': result.get('error_message'),
                'review_results': result.get('review_results', {})
            }
            cache.final_result(cacheable_result, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)

            return review_results

        except asyncio.TimeoutError:
            logger.error(f"AI审查工作流超时（{self.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']}")

        return {
            "current_stage": "start",
            "status": "processing",
            "messages": [AIMessage(content="")]
        }

    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')}")

        return {
            "messages": [AIMessage(content="进度初始化完成")]
        }
    
    async def _ai_review_node_check_item(self, state: AIReviewState) -> AIReviewState:
        """
        检查当前项是否需要AI审查 - 新版本

        执行流程：
        1. 终止信号检查
        2. 解析审查项配置
        3. 开始审查
        5. 汇总结果并构建响应
        """
        try:
            logger.info(f"AI审查项检查开始执行，任务ID: {self.task_info.callback_task_id}")

            # 1️ 终止信号检查
            if await self.workflow_manager.check_terminate_signal(state["callback_task_id"]):
                logger.warning(f"AI审查项检查检测到终止信号，任务ID: {state['callback_task_id']}")
                return {
                    "status": "terminated",
                    "current_stage": "ai_review_check_item",
                    "messages": [AIMessage(content="检测到终止信号")]
                }

            # 2️ 解析审查项配置
            review_func_mapping: Dict[str, Union[str, List[str]]] = {
                'sensitive_word_check': 'sensitive_word_check',
                'semantic_logic_check': 'check_semantic_logic',
                'completeness_check': 'check_completeness',
                'timeliness_check': 'timeliness_basis_reviewer',
                'timeliness_content_check': 'timeliness_content_reviewer',
                'reference_check': 'reference_basis_reviewer',
                'sensitive_check': 'check_sensitive',
                'non_parameter_compliance_check': 'check_non_parameter_compliance',
                'parameter_compliance_check': 'check_parameter_compliance'
            }

            # 获取审查项配置
            review_item_config_raw = self.task_info.get_review_item_config_list()

            # 将review_item_config中的值拆分成chapter_code和func_name 如{['basis':["sensitive_word_check"，"timeliness_basis_reviewer"]]}
            review_item_config = self.core_fun._replace_review_suffix(review_item_config_raw, review_func_mapping)

            # 【新增】处理时效性审查的章节映射：
            # - basis 章节使用 timeliness_basis_reviewer（编制依据时效性）
            # - 其他章节使用 timeliness_content_reviewer（内容时效性）
            processed_config = []
            for item in review_item_config:
                if '_' in item:
                    chapter_code, func_name = item.split('_', 1)
                    # 如果是时效性审查，根据章节选择正确的审查器
                    if func_name == 'timeliness_basis_reviewer':
                        if chapter_code == 'basis':
                            # basis 章节保持使用 timeliness_basis_reviewer
                            processed_config.append(item)
                        else:
                            # 其他章节使用 timeliness_content_reviewer
                            processed_config.append(f"{chapter_code}_timeliness_content_reviewer")
                        continue
                processed_config.append(item)
            review_item_config = processed_config

            # 根据标准配置对review_item_config进行排序
            review_item_dict_sorted = self.core_fun._check_item_mapping_order(review_item_config)
            logger.info(f"审查项配置解析完成: {review_item_dict_sorted}")
            
            # 3️⃣ 获取结构化内容
            original_chunks = state.get("structured_content", {}).get("chunks", [])
            
            # 安全获取 outline - 兼容无目录的情况（如某些DOCX文档）
            outline_data = state.get("structured_content", {}).get("outline", {})
            if isinstance(outline_data, dict):
                original_outline = outline_data.get("chapters", [])
            else:
                # outline 不是字典（可能是列表或None），视为无目录
                original_outline = []
                logger.warning("文档 outline 格式异常或非字典类型，视为无目录结构")
            
            # 如果没有目录，记录警告并继续（跳过目录审查）
            if not original_outline:
                logger.warning("文档未检测到目录结构，将跳过目录完整性审查")
            
            outline_content_list = []
            
            def extract_original_recursive(content):
                """递归提取 original 字段，包括主目录和所有子目录"""
                result = []
                if isinstance(content, dict):
                    # 提取当前层级的 original
                    if "original" in content:
                        result.append(content["original"])
                    # 递归提取 subsections
                    if "subsections" in content and isinstance(content["subsections"], list):
                        for subsection in content["subsections"]:
                            result.extend(extract_original_recursive(subsection))
                return result

            for content in original_outline:
                # 递归提取主目录和子目录的 original 字段
                originals = extract_original_recursive(content)
                outline_content_list.extend(originals)

            # 4. 最终拼接成字符串（列表join效率远高于str+=）
            outline_content_str = "".join(outline_content_list)
            
            # 预处理：根据 review_item_dict_sorted 中的 key 对 structured_content 进行筛选
            filtered_chunks = [
                chunk for chunk in original_chunks
                if chunk.get("chapter_classification") in review_item_dict_sorted.keys()
            ]

            # filtered_outline = [
            #     outline for outline in original_outline
            #     if outline.get("chapter_classification") in review_item_dict_sorted.keys()
            # ]

            # 筛选完整性存在完整性审查的分类，将其整章进行合并
            filtered_chunks = self.core_fun._merge_chunks_for_completeness_check(
                filtered_chunks, review_item_dict_sorted
            )

            cache.filtered_chunks(filtered_chunks, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
            # 更新 chunks 和 structured_content
            # chunks = filtered_chunks
            
            # structured_content["chunks"] = chunks

            total_chapters = len(review_item_dict_sorted)
            cache.filtered_chunks(review_item_dict_sorted, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
            # 统计所有 filtered_chunks 作为总块数（与实际处理的块数保持一致）
            all_check_items = []
            for check_list in review_item_dict_sorted.values():
                all_check_items.extend(check_list)  # 把每个分类的检查项加入总列表

            # 统计所有 filtered_chunks 作为总块数（与实际处理的块数保持一致）
            # 注意：+1 为目录审查单元（系统强制添加，不在用户配置的 review_item_config 中）
            total_chunks = len(filtered_chunks) + 1

            # 初始化issues列表
            all_issues = []
            completed_chunks = 0
            # 添加目录章节内容
            catalogue = [{
                    "chunk_id": "outline_1",
                    "page": 1,
                    "content": outline_content_str,
                    "section_label": "目录",
                    "project_plan_type": "catalogue",
                    "chapter_classification": "catalogue",
                    "element_tag": {
                        "chunk_id": "outline_1",
                        "page": 1,
                        "serial_number": "1"
                    },
                    "chapter": "目录",
                    "title": "目录",
                    "original_content": outline_content_str,
                    "is_complete_field": True
                }
            ]
            chapter_chunks_map, chapter_names = self.core_fun._group_chunks_by_chapter(filtered_chunks)


            logger.info(f"内容分组完成，共 {len(chapter_chunks_map)} 个章节")
            cache.filtered_chunks(chapter_chunks_map, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
            await self.core_fun._send_start_review_progress(state,total_chunks, chapter_names)
            # 6️ 按章节处理
            for chapter_idx, (chapter_code, func_names) in enumerate(review_item_dict_sorted.items()):
                logger.info(f" 处理章节 [{chapter_idx+1}/{total_chapters}]: {chapter_code}，包含 {len(func_names)} 个审查任务")
                # logger.info(f"🔍 章节处理前: all_issues数量={len(all_issues)}")  # 调试日志

                # 终止信号检查（章节级别）
                if await self.workflow_manager.check_terminate_signal(state["callback_task_id"]):
                    logger.warning(f"章节审查检测到终止信号，任务ID: {state['callback_task_id']}")
                    break

                # 获取当前章节的内容
                chapter_content = chapter_chunks_map.get(chapter_code, [])
                if not chapter_content:
                    logger.warning(f"章节 {chapter_code} 没有找到对应内容，跳过")
                    continue

                chunks_completed, all_issues = await self.core_fun._process_chapter_item(
                    chapter_code, chapter_content, func_names, state, all_issues, completed_chunks, total_chunks
                )
                # 更新已完成块数
                completed_chunks += chunks_completed

                logger.info(f"章节 {chapter_code} 处理完成")

            # 主流程完成后，串行处理 catalogue（目录审查）
            # 注意：catalogue 是系统强制添加的审查单元，已计入 total_chunks
            logger.info("开始处理目录审查（catalogue）")
            # 目录审查只执行完整性检查（目录缺失统计已整合到 check_completeness 中）
            chunks_completed, all_issues = await self.core_fun._process_chapter_item(
                "catalogue",                 # chapter_code
                catalogue,                   # chapter_content
                ["check_completeness"],      # 只执行完整性检查（包含目录缺失统计）
                state,
                all_issues,
                completed_chunks,
                total_chunks
            )
            completed_chunks += chunks_completed  # 更新已完成块数
            logger.info("目录审查处理完成")

            logger.info(f"all_issues_结果调试: {len(all_issues)} 个问题")
            # 7️ 汇总结果
            summary = self.inter_tool._aggregate_results(all_issues)

            # 8️ 构建完整的响应结构（兼容 execute() 方法的期望格式）
            review_results = {
                # 兼容旧版格式的字段
                "total_units": total_chunks,
                "successful_units": completed_chunks,
                "failed_units": max(0, total_chunks - completed_chunks),
                "review_results": all_issues,  # 审查结果列表
                "summary": summary,

                # 额外的元信息
                "callback_task_id": state["callback_task_id"],
                "file_name": state.get("file_name", ""),
                "user_id": state["user_id"],
                "current": 100,
                "stage_name": "审查项检查结果",
                "status": "full_review_result",
                "message": f"审查项检查完成，共发现{summary.get('total_issues', 0)}个问题",
                "updated_at": int(time.time())
            }

            logger.info(f"AI审查项检查执行成功，任务ID: {state['callback_task_id']}, 总单元数: {total_chunks}, 已完成: {completed_chunks}, 共发现{summary.get('total_issues', 0)}个问题")

            # 返回新的状态
            return {
                "current_stage": "ai_review_check_item_completed",
                "review_results": review_results,
                "status": "completed",
                "messages": [AIMessage(content=f"AI审查项检查完成，共发现{summary.get('total_issues', 0)}个问题")]
            }

        except Exception as e:
            logger.error(f"AI审查项检查执行失败，任务ID: {state['callback_task_id']}, 错误: {str(e)}", exc_info=True)

            # 返回错误状态
            return {
                "current_stage": "ai_review_check_item_failed",
                "error_message": str(e),
                "status": "failed",
                "messages": [AIMessage(content=f"AI审查项检查失败: {str(e)}")]
            }

    async def _save_results_node(self, state: AIReviewState) -> AIReviewState:
        """
        保存结果节点 - 将审查结果存储到本地文件或数据库

        Args:
            state: AI审查工作流状态，包含审查结果

        Returns:
            AIReviewState: 更新后的工作流状态

        Note:
            ⚠️ 根据方案D + 决策2（方案A-方式1）的优化：
            - AI审查工作流作为子图嵌套在外层任务链中时，不在此处保存结果
            - 外层任务链会在报告生成完成后一次性保存完整结果（文档 + AI审查 + 报告）
            - 这解决了原有的"AI审查完成就保存，导致结果不完整"的问题
            - 当前实现：跳过保存，仅返回状态更新
        """
        try:
            logger.info(f"AI审查子图完成，跳过保存（由外层任务链统一保存），任务ID: {state['callback_task_id']}")

            # ⚠️ 注意：根据方案A-方式1，此处不保存结果
            # 保存工作由外层任务链的 _report_generation_node 调用 _save_complete_results 完成

            return {
                "current_stage": "save_results",
                "messages": [AIMessage(content="AI审查结果将由外层任务链统一保存")]
            }

        except Exception as e:
            logger.error(f"保存审查结果节点执行失败: {str(e)}", exc_info=True)
            return {
                "current_stage": "save_results_failed",
                "error_message": f"保存结果节点失败: {str(e)}",
                "status": "failed",
                "messages": [AIMessage(content=f"保存结果节点失败: {str(e)}")]
            }

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

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

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

        Note:
            ⚠️ 重要修改（方案D优化）：
            - AI审查工作流作为子图嵌套时，不应标记整体任务完成
            - 仅标记 AI审查阶段完成（stage_status），不设置 overall_task_status
            - overall_task_status 只由外层任务链的 _complete_chain_node 统一设置
            - 这解决了前端误判"AI审查完成 = 整体任务完成"的问题
        """
        logger.info(f"AI审查阶段完成（子图）: {state['file_id']}")

        # 更新AI审查阶段完成状态（不标记整体任务完成）
        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",  # 阶段状态：AI审查本身已完成
                message="AI审查阶段完成，等待报告生成",
                overall_task_status="processing",  # ⚠️ 关键：整体任务仍在处理中
                event_type="processing"
            )

        return {
            "current_stage": "complete",
            "status": "completed",  # 子图内部状态：AI审查完成
            # ⚠️ 注意：不设置 overall_task_status，由外层任务链管理
            "messages": [AIMessage(content="AI审查阶段完成")]
        }

    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"{state['error_message']}",
                overall_task_status="failed",
                event_type="error"
            )

        return {
            "status": "failed",
            "current_stage": "error_handler",
            "messages": [AIMessage(content=f"错误处理: {state['error_message']}")]
        }

    async def _terminate_node(self, state: AIReviewState) -> AIReviewState:
        """
        终止节点 - 处理任务终止请求

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

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

        Note:
            当检测到终止信号时，工作流跳转到此节点
            设置状态为terminated，清理资源，通过进度管理器发送终止通知
        """
        logger.warning(f"AI审查任务已终止: {state['callback_task_id']}")

        # 更新终止状态
        if state["progress_manager"]:
            await state["progress_manager"].update_stage_progress(
                callback_task_id=state["callback_task_id"],
                stage_name="AI审查",
                current=state.get("current", 0),
                status="terminated",
                message="任务已被用户终止",
                overall_task_status="terminated",
                event_type="terminated"
            )

        # 清理 Redis 终止信号
        await self.workflow_manager.clear_terminate_signal(state["callback_task_id"])

        return {
            "status": "terminated",
            "current_stage": "terminated",
            "messages": [AIMessage(content="任务已被终止")]
        }

    def _should_check_item_or_dimensions(self, state: AIReviewState) -> str:
        """
        检查应该使用 review_item_config

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

        Returns:
            str: "activate_ai_review_check_item" 使用 review_item_config（章节_审查维度格式）

        Note:
            基于验证逻辑：
            如果 review_item_config 不为空，走 ai_review_check_item 节点
        """
        # 获取 review_item_config 列表（使用 get_review_item_config_list 方法）
        review_item_config = self.task_info.get_review_item_config_list()

        # 使用 review_item_config（章节_审查维度格式）
        logger.info(f"使用 review_item_config 进行审查: {review_item_config}")
        return "activate_ai_review_check_item"

    def _should_terminate_or_error(self, state: AIReviewState) -> str:
        """
        检查是否应该终止或发生错误

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

        Returns:
            str: "terminate", "success", 或 "error"

        Note:
            1. 优先检查终止信号
            2. 检查是否有错误
            3. 都没有则返回 success
        """
        # 同步检查状态字段（避免在条件边中使用异步）
        if state.get("status") == "terminated":
            return "terminate"

        # 检查是否有错误消息
        if state.get("error_message"):
            return "error"

        # 默认返回成功
        return "success"

    def _get_workflow_graph(self):
        """获取工作流图（可视化输出）"""
        try:
            grandalf_graph = self.graph.get_graph()
            grandalf_graph.print_ascii()
            self._save_workflow_graph(grandalf_graph)

        except Exception as e:
            logger.warning(f"生成工作流图失败: {str(e)}")

    def _save_workflow_graph(self, graph):
        """保存工作流图到temp文件夹"""
        try:
            # 创建temp目录
            temp_dir = "temp"

            file_path = os.path.join(temp_dir, f"ai_review_workflow_graph.png")

            png_data = graph.draw_mermaid_png()

            # 保存到文件
            with open(file_path, "wb") as f:
                f.write(png_data)

            logger.info(f"工作流图已保存到: {file_path}")

        except Exception as e:
            try:
                
                ascii_file = os.path.join("temp", f"ai_review_workflow_graph.txt")
                with open(ascii_file, 'w', encoding='utf-8') as f:
                    graph.print_ascii(file=f)
                logger.info(f"工作流ASCII图已保存到: {ascii_file}")
            except Exception as ascii_error:
                logger.warning(f"保存ASCII图也失败: {str(ascii_error)}")

            logger.warning(f"保存工作流图PNG失败: {str(e)}")
 
    def _extract_prep_basis_content(self, structured_content: Dict[str, Any]) -> str:
        """
        从结构化内容中提取编制依据文本

        Args:
            structured_content: 结构化内容字典，包含chunks数组

        Returns:
            str: 编制依据文本内容，如果没有找到则返回空字符串
        """
        try:
            # 从chunks中查找包含编制依据的章节
            chunks = structured_content.get('chunks', [])
            if not chunks:
                logger.warning("结构化内容中没有chunks数据")
                return ""

            found_basis_content = []

            for chunk in chunks:
                chunk_content = chunk.get('content', '')

                if not chunk_content or not isinstance(chunk_content, str):
                    continue

                # 检查content中是否包含编制依据章节
                if '编制依据' in chunk_content:
                    # 检查是否含有书名号《》
                    if '《' in chunk_content and '》' in chunk_content:
                        logger.info(f"找到编制依据章节且含有书名号")
                        found_basis_content.append(chunk_content)

            if found_basis_content:
                combined_content = '\n\n'.join(found_basis_content)
                logger.info(f"成功提取编制依据内容，长度: {len(combined_content)}")
                return combined_content.strip()

            logger.warning("未在结构化内容中找到编制依据章节和书名号")
            return ""

        except Exception as e:
            logger.error(f"提取编制依据内容失败: {str(e)}")
            return ""

    async def _get_status(self) -> dict:
        """获取工作流状态"""
        if self.progress_manager:
            return await self.progress_manager.get_progress(self.callback_task_id)
        return {}


