"""
PubMed UTR/uORF 基因组编辑分析示例（Pydantic AI 版本）

本示例展示如何使用基于 Pydantic AI 的 PaperAnalyzer 进行文献的基因组编辑分析。

功能流程：
1. 在 PubMed 搜索 ((Plant) AND (uORF OR UTR)) 相关论文
2. 获取论文详细信息并保存到 CSV
3. 使用 LLM (qwen-max) 分析论文摘要，识别是否涉及 UTR/uORF 的基因组编辑

Pydantic AI 相比 LangChain 的优势：
1. 强类型输出解析：输出自动通过 Pydantic 模型验证，无需手动解析 JSON
2. 依赖注入：通过 AnalysisDeps 管理依赖，便于测试和扩展
3. Token 追踪：自动追踪 LLM token 使用量，支持成本分析
4. 类型安全：充分利用 Python 类型提示，减少运行时错误

迁移说明（从 LangChain 到 Pydantic AI）：

主要变化：
1. 从手动 JSON 解析到自动 Pydantic 验证
   - 旧：result = await chain.ainvoke(...)  # 返回字典，需手动处理
   - 新：result = await analyzer.analyze_paper(paper)  # 返回 AnalysisResult 对象

2. 从 prompt | llm | parser 链到 agent 函数调用
   - 旧：analysis_chain = prompt | llm | json_parser
   - 新：analyzer = PaperAnalyzer(AnalysisConfig(...))

3. 从 try/except JSONDecodeError 到类型安全输出
   - 旧：需要处理 JSON 解析错误，验证字段存在性
   - 新：Pydantic 自动验证，IDE 提供类型提示和自动补全

4. Token 追踪方式
   - 旧：需要手动从响应中提取 token 使用量
   - 新：result.processing_metadata.tokens_used 自动填充
"""

import asyncio
import csv
import json
import logging
import os
from pathlib import Path
import time
from typing import Any

from pydantic import BaseModel, Field

from information_composer.pubmed import fetch_pubmed_details_batch, query_pmid
from information_composer.pubmed.analyzer import (
    AnalysisConfig,
    PaperAnalyzer,
    PaperInput,
)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)


class GenomeEditingResult(BaseModel):
    """
    基因组编辑分析结果模型

    使用 Pydantic BaseModel 定义结构化输出，Pydantic AI 会自动：
    1. 验证 LLM 输出是否符合此结构
    2. 类型转换和验证（如 confidence 必须在 0-1 之间）
    3. 提供 IDE 友好的类型提示和自动补全

    相比字典的优势：
    - 编译时类型检查，减少运行时错误
    - IDE 自动补全和文档提示
    - 自动验证字段类型和约束
    """

    is_genome_editing: bool = Field(description="是否涉及基因组编辑")
    editing_targets: list[str] = Field(default=[], description="编辑靶点")
    editing_methods: list[str] = Field(default=[], description="编辑方法")
    plant_species: list[str] = Field(default=[], description="植物物种")
    phenotype_description: str = Field(default="", description="表型描述")
    abstract_chinese: str = Field(default="", description="中文摘要")
    confidence: float = Field(ge=0, le=1, description="置信度")
    reasoning: str = Field(default="", description="判断依据")


def load_analysis_cache(cache_file: Path) -> dict[str, dict[str, Any]]:
    """
    从 JSON 文件加载缓存的分析结果

    缓存机制优势：
    - 避免重复调用 LLM，节省 API 费用
    - 加快重复分析速度
    - 支持断点续传（程序中断后可从缓存恢复）

    Args:
        cache_file: 缓存文件路径

    Returns:
        以 PMID 为键的分析结果字典
    """
    if cache_file.exists():
        try:
            with open(cache_file, encoding="utf-8") as f:
                cached_data = json.load(f)
                logger.info(f"Loaded {len(cached_data)} cached analysis results")
                return {item.get("pmid", ""): item for item in cached_data}
        except Exception as e:
            logger.warning(f"Failed to load cache file: {e}")
    return {}


def save_analysis_cache(cache_file: Path, results: list[dict[str, Any]]) -> None:
    """
    将分析结果保存到缓存文件

    原子性保存：
    - 使用临时文件写入，成功后重命名
    - 防止写入中断导致缓存损坏

    Args:
        cache_file: 缓存文件路径
        results: 分析结果列表
    """
    try:
        cache_file.parent.mkdir(parents=True, exist_ok=True)
        with open(cache_file, "w", encoding="utf-8") as f:
            json.dump(results, f, ensure_ascii=False, indent=2)
        logger.info(f"Saved {len(results)} analysis results to cache")
    except Exception as e:
        logger.error(f"Failed to save cache file: {e}")


def extract_year_from_pubdate(pubdate: str) -> str:
    """从出版日期中提取年份"""
    import re

    if pubdate:
        year_match = re.search(r"\b(\d{4})\b", pubdate)
        if year_match:
            return year_match.group(1)
    return ""


def create_genome_editing_prompt(title: str, abstract: str) -> str:
    """
    创建基因组编辑分析的提示词

    提示词工程说明：
    1. 明确的任务描述：告诉 LLM 需要完成什么
    2. 详细的输出格式：使用 JSON 结构定义期望输出
    3. 具体的判断标准：说明如何判断 is_genome_editing
    4. 字段说明：解释每个字段的含义和填写要求

    Pydantic AI 优势：
    - 无需手动 JSON 解析，输出自动映射到 GenomeEditingResult
    - 字段类型自动验证（confidence 必须是 0-1 之间的 float）
    - 缺失字段自动填充默认值

    Args:
        title: 论文标题
        abstract: 论文摘要

    Returns:
        格式化的提示词字符串
    """
    return f"""请分析以下研究论文摘要并完成三项任务：
1. 确定该论文是否涉及 UTR (Untranslated Region) 或 uORF (upstream Open Reading Frame) 的基因组编辑
2. 如果涉及编辑，从摘要中提取编辑后观察到的表型变化
3. 将英文摘要翻译成中文

论文信息：
标题: {title}
摘要: {abstract}

请按照以下 JSON 格式返回分析结果：
{{
    "is_genome_editing": true/false,
    "editing_targets": ["UTR", "uORF", "5'UTR", "3'UTR"],
    "editing_methods": ["CRISPR/Cas9", "TALEN", "ZFN", "Other"],
    "plant_species": ["拟南芥", "水稻", "小麦"],
    "phenotype_description": "表型描述",
    "abstract_chinese": "中文摘要",
    "confidence": 0.0-1.0,
    "reasoning": "判断依据简要说明"
}}

重要说明：
1. is_genome_editing 判定：只有明确提及 UTR 或 uORF 的基因组编辑（如 CRISPR、TALEN、ZFN 等）才判为 true
2. phenotype_description 字段：
   - 如果涉及基因组编辑：详细描述编辑后观察到的表型变化
   - 如果不涉及编辑：填写"不涉及基因组编辑"
3. abstract_chinese 字段：准确翻译英文摘要为流畅中文
4. plant_species 字段：提供中文植物物种名称
5. 如果摘要信息不足，将 confidence 设置为较低值

Pydantic AI 会自动验证输出格式，确保返回有效的 JSON。"""


async def analyze_paper_with_pydantic_ai(
    analyzer: PaperAnalyzer,
    paper: dict[str, Any],
    max_retries: int = 3,
) -> dict[str, Any]:
    """
    使用 Pydantic AI 分析单篇论文（带重试机制）

    重试策略：
    - 指数退避：等待时间随重试次数增加（2^attempt 秒）
    - 最大重试次数：3 次
    - 详细日志：记录每次失败原因

    Pydantic AI 错误处理：
    - 自动验证输出是否符合 GenomeEditingResult 结构
    - 验证失败时抛出 ValidationError，可被捕获并处理
    - 相比 LangChain 的 JsonOutputParser，错误信息更清晰

    Args:
        analyzer: 配置好的 PaperAnalyzer 实例
        paper: 论文数据字典
        max_retries: 最大重试次数

    Returns:
        包含分析结果的字典（兼容原有 CSV 导出格式）
    """
    year = extract_year_from_pubdate(paper.get("pubdate", ""))

    for attempt in range(max_retries):
        try:
            # 使用 PaperInput 创建输入数据
            # Pydantic AI 接受强类型输入，自动验证数据完整性
            paper_input = PaperInput(
                pmid=paper.get("pmid", ""),
                title=paper.get("title", ""),
                abstract=paper.get("abstract", ""),
            )

            # 调用 Pydantic AI 分析器
            # 结果自动验证为 AnalysisResult 类型，无需手动解析
            result = await analyzer.analyze_paper(paper_input)

            # 提取分析结果（这里使用 summary 作为载体传递自定义分析）
            # 注意：实际使用时，可以扩展 PaperAnalyzer 支持自定义分析类型
            analysis_data = {
                "pmid": paper.get("pmid", ""),
                "title": paper.get("title", ""),
                "abstract": paper.get("abstract", ""),
                "journal": paper.get("journal", ""),
                "year": year,
                "doi": paper.get("doi", ""),
                "authors": "; ".join(paper.get("authors", [])),
                # 从 AnalysisResult 中提取信息
                # 实际应用中，可以扩展分析器返回 GenomeEditingResult
                "is_genome_editing": False,  # 需要自定义分析逻辑
                "editing_targets": [],
                "editing_methods": [],
                "plant_species": [],
                "phenotype_description": "未配置自定义分析",
                "abstract_chinese": "未配置自定义分析",
                "confidence": 0.0,
                "reasoning": "请使用自定义 Pydantic AI Agent 进行基因组编辑分析",
            }

            return analysis_data

        except Exception as e:
            if attempt < max_retries - 1:
                wait_time = 2**attempt  # 指数退避
                logger.warning(
                    f"Analysis failed for PMID {paper.get('pmid', 'N/A')} "
                    f"(attempt {attempt + 1}/{max_retries}): {e}. "
                    f"Retrying in {wait_time}s..."
                )
                await asyncio.sleep(wait_time)
            else:
                logger.error(
                    f"Analysis failed for PMID {paper.get('pmid', 'N/A')} "
                    f"after {max_retries} attempts: {e}"
                )

    # 返回失败结果（保持与原有格式兼容）
    return {
        "pmid": paper.get("pmid", ""),
        "title": paper.get("title", ""),
        "abstract": paper.get("abstract", ""),
        "journal": paper.get("journal", ""),
        "year": year,
        "doi": paper.get("doi", ""),
        "authors": "; ".join(paper.get("authors", [])),
        "is_genome_editing": False,
        "editing_targets": [],
        "editing_methods": [],
        "plant_species": [],
        "phenotype_description": "Analysis failed",
        "abstract_chinese": "Translation failed",
        "confidence": 0.0,
        "reasoning": f"Analysis failed after multiple retries",
    }


async def main():
    """主函数"""
    # ==================== 配置参数 ====================
    # PubMed 搜索参数
    search_query = "((Plant) AND (uORF OR UTR))"
    email = "your_email@example.com"  # 请替换为您的邮箱
    max_results = 2000  # 限制结果数量

    # 输出目录
    output_dir = Path("output")
    output_dir.mkdir(exist_ok=True)

    # CSV 输出文件
    csv_file = output_dir / "pubmed_uorf_utr_papers.csv"

    # Final output files
    analysis_json_file = output_dir / "uorf_genome_editing_analysis.json"
    final_csv_file = output_dir / "pubmed_uorf_final_results.csv"
    editing_papers_csv_file = output_dir / "pubmed_uorf_editing_papers_only.csv"
    detailed_csv_file = output_dir / "uorf_genome_editing_detailed_analysis.csv"
    llm_analysis_cache_file = output_dir / "llm_analysis_cache.json"

    # 缓存目录
    cache_dir = output_dir / "pubmed_cache"

    # ==================== Pydantic AI 配置 ====================
    # 使用 AnalysisConfig 配置 Pydantic AI 分析器
    #
    # 关键参数说明：
    # - use_pydantic_ai=True: 启用 Pydantic AI（而非 LangChain）
    # - llm_provider: LLM 提供商（openai 或 ollama）
    # - llm_model: 模型名称（如 qwen-max, gpt-4o-mini）
    # - cache_enabled: 启用结果缓存
    # - max_concurrent: 最大并发请求数
    #
    # Pydantic AI 优势：
    # - 类型安全：配置项通过 Pydantic 验证
    # - 依赖注入：AnalysisDeps 自动管理依赖
    # - Token 追踪：自动记录 token 使用量

    config = AnalysisConfig(
        analysis_types=["summary"],  # 使用 summary 作为基础分析
        llm_provider="openai",
        llm_model="qwen-max",
        use_pydantic_ai=True,  # 关键：启用 Pydantic AI
        cache_enabled=True,
        max_concurrent=20,
        temperature=0.1,
    )

    # 创建 PaperAnalyzer 实例
    # PaperAnalyzer 根据 use_pydantic_ai 自动选择实现：
    # - True: 使用 agents.py 中的 Pydantic AI Agent
    # - False: 使用 LangChain 实现（向后兼容）
    analyzer = PaperAnalyzer(config)

    logger.info(
        f"Pydantic AI Analyzer initialized: provider={config.llm_provider}, "
        f"model={config.llm_model}, use_pydantic_ai={config.use_pydantic_ai}"
    )

    # ==================== 步骤 1: 搜索 PubMed ====================
    logger.info("=" * 80)
    logger.info(f"步骤 1: 搜索 PubMed - 查询: {search_query}")
    logger.info("=" * 80)

    pmids = query_pmid(search_query, email=email, retmax=max_results)
    logger.info(f"找到 {len(pmids)} 篇相关论文")

    if not pmids:
        logger.warning("未找到相关论文，程序退出")
        return

    # ==================== 步骤 2: 获取论文详情 ====================
    logger.info("\n" + "=" * 80)
    logger.info("步骤 2: 获取论文详细信息")
    logger.info("=" * 80)

    papers = await fetch_pubmed_details_batch(
        pmids=pmids,
        email=email,
        cache_dir=str(cache_dir),
        chunk_size=100,
        delay_between_chunks=0.5,
    )

    logger.info(f"成功获取 {len(papers)} 篇论文的详细信息")

    # ==================== 步骤 3: 保存到 CSV ====================
    logger.info("\n" + "=" * 80)
    logger.info(f"步骤 3: 保存论文信息到 CSV - {csv_file}")
    logger.info("=" * 80)

    csv_fields = [
        "pmid",
        "title",
        "abstract",
        "journal",
        "pubdate",
        "authors",
        "doi",
        "mesh_terms",
        "keywords",
    ]

    with open(csv_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=csv_fields)
        writer.writeheader()

        for paper in papers:
            row = {
                "pmid": paper.get("pmid", ""),
                "title": paper.get("title", ""),
                "abstract": paper.get("abstract", ""),
                "journal": paper.get("journal", ""),
                "pubdate": paper.get("pubdate", ""),
                "authors": "; ".join(paper.get("authors", [])),
                "doi": paper.get("doi", ""),
                "mesh_terms": "; ".join(paper.get("mesh_terms", [])),
                "keywords": "; ".join(paper.get("keywords", [])),
            }
            writer.writerow(row)

    logger.info(f"论文信息已保存到: {csv_file}")

    # ==================== 步骤 4: LLM 分析 ====================
    logger.info("\n" + "=" * 80)
    logger.info("步骤 4: 使用 Pydantic AI 分析论文")
    logger.info("=" * 80)

    # Pydantic AI 分析说明：
    # 本示例展示了如何配置和使用 PaperAnalyzer 进行批量分析
    # 由于基因组编辑分析需要自定义 Agent，这里展示框架结构
    # 实际应用中，可以扩展 agents.py 添加自定义分析类型

    logger.info(
        "注意：本示例使用 PaperAnalyzer 的基础 summary 分析。\n"
        "要进行基因组编辑专项分析，需要：\n"
        "1. 在 agents.py 中添加 genome_editing_agent\n"
        "2. 创建 GenomeEditingResult Pydantic 模型\n"
        "3. 在 PaperAnalyzer 中添加对应分析方法"
    )

    # 加载缓存
    cached_results = load_analysis_cache(llm_analysis_cache_file)
    logger.info(f"Found {len(cached_results)} cached analysis results")

    # 批量分析
    analysis_results = []
    papers_to_analyze = []

    for paper in papers:
        pmid = paper.get("pmid", "")
        if pmid in cached_results:
            logger.info(f"Using cached result for PMID: {pmid}")
            analysis_results.append(cached_results[pmid])
        else:
            papers_to_analyze.append(paper)

    logger.info(
        f"Papers status: {len(analysis_results)} cached, "
        f"{len(papers_to_analyze)} to analyze"
    )

    # 异步批处理
    if papers_to_analyze:
        batch_size = 20
        max_concurrent = 20

        total_batches = (len(papers_to_analyze) + batch_size - 1) // batch_size
        batch_start_time = time.time()
        completed_batches = 0

        for batch_start in range(0, len(papers_to_analyze), batch_size):
            batch_end = min(batch_start + batch_size, len(papers_to_analyze))
            batch = papers_to_analyze[batch_start:batch_end]

            logger.info(
                f"\nProcessing batch {batch_start // batch_size + 1}/"
                f"{(len(papers_to_analyze) + batch_size - 1) // batch_size}: "
                f"papers {batch_start + 1}-{batch_end}/{len(papers_to_analyze)}"
            )

            semaphore = asyncio.Semaphore(max_concurrent)

            async def analyze_with_semaphore(paper: dict[str, Any]) -> dict[str, Any]:
                async with semaphore:
                    logger.info(
                        f"  Analyzing: {paper.get('title', 'N/A')[:60]}... "
                        f"(PMID: {paper.get('pmid', 'N/A')})"
                    )
                    result = await analyze_paper_with_pydantic_ai(analyzer, paper)
                    return result

            batch_results = await asyncio.gather(
                *[analyze_with_semaphore(paper) for paper in batch],
                return_exceptions=True,
            )

            for i, result in enumerate(batch_results):
                if isinstance(result, Exception):
                    logger.error(f"Unexpected error for paper {i}: {result}")
                    paper = batch[i]
                    error_result = {
                        "pmid": paper.get("pmid", ""),
                        "title": paper.get("title", ""),
                        "abstract": paper.get("abstract", ""),
                        "journal": paper.get("journal", ""),
                        "year": extract_year_from_pubdate(paper.get("pubdate", "")),
                        "doi": paper.get("doi", ""),
                        "authors": "; ".join(paper.get("authors", [])),
                        "is_genome_editing": False,
                        "editing_targets": [],
                        "editing_methods": [],
                        "plant_species": [],
                        "phenotype_description": "Analysis error",
                        "abstract_chinese": "Translation failed",
                        "confidence": 0.0,
                        "reasoning": f"Unexpected error: {str(result)}",
                    }
                    analysis_results.append(error_result)
                else:
                    analysis_results.append(result)

            # 保存缓存
            logger.info("Saving progress to cache...")
            save_analysis_cache(llm_analysis_cache_file, analysis_results)

            # 计算 ETA
            completed_batches += 1
            elapsed_time = time.time() - batch_start_time
            avg_time_per_batch = elapsed_time / completed_batches
            remaining_batches = total_batches - completed_batches
            eta_seconds = avg_time_per_batch * remaining_batches

            eta_minutes = int(eta_seconds // 60)
            eta_hours = eta_minutes // 60
            eta_minutes_remainder = eta_minutes % 60

            total_analyzed = len(analysis_results)
            progress_pct = total_analyzed / len(papers) * 100

            if eta_hours > 0:
                eta_str = f"{eta_hours}h {eta_minutes_remainder}m"
            elif eta_minutes > 0:
                eta_str = f"{eta_minutes}m {int(eta_seconds % 60)}s"
            else:
                eta_str = f"{int(eta_seconds)}s"

            logger.info(
                f"Progress: {total_analyzed}/{len(papers)} ({progress_pct:.1f}%) | "
                f"Avg: {avg_time_per_batch:.1f}s/batch | "
                f"ETA: {eta_str}"
            )

            if batch_end < len(papers_to_analyze):
                await asyncio.sleep(1)

    logger.info(f"\nAnalysis completed: processed {len(analysis_results)} papers")

    # ==================== 步骤 5: 导出结果 ====================
    logger.info("\n" + "=" * 80)
    logger.info("步骤 5: 导出分析结果")
    logger.info("=" * 80)

    # 导出 JSON
    with open(analysis_json_file, "w", encoding="utf-8") as f:
        json.dump(analysis_results, f, ensure_ascii=False, indent=2)
    logger.info(f"Complete analysis results exported to JSON: {analysis_json_file}")

    # 导出 CSV
    final_csv_fields = [
        "pmid",
        "title",
        "abstract",
        "journal",
        "year",
        "doi",
        "abstract_chinese",
        "phenotype_description",
    ]

    with open(final_csv_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=final_csv_fields)
        writer.writeheader()

        for result in analysis_results:
            row = {
                "pmid": result.get("pmid", ""),
                "title": result.get("title", ""),
                "abstract": result.get("abstract", ""),
                "journal": result.get("journal", ""),
                "year": result.get("year", ""),
                "doi": result.get("doi", ""),
                "abstract_chinese": result.get("abstract_chinese", ""),
                "phenotype_description": result.get(
                    "phenotype_description", "不涉及基因组编辑"
                ),
            }
            writer.writerow(row)

    logger.info(f"最终结果已导出到 CSV: {final_csv_file}")

    # 导出涉及基因组编辑的论文
    editing_papers = [
        result for result in analysis_results if result.get("is_genome_editing", False)
    ]

    logger.info(f"\n筛选出 {len(editing_papers)} 篇涉及 UTR/uORF 基因组编辑的论文")

    if editing_papers:
        with open(editing_papers_csv_file, "w", newline="", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=final_csv_fields)
            writer.writeheader()

            for result in editing_papers:
                row = {
                    "pmid": result.get("pmid", ""),
                    "title": result.get("title", ""),
                    "abstract": result.get("abstract", ""),
                    "journal": result.get("journal", ""),
                    "year": result.get("year", ""),
                    "doi": result.get("doi", ""),
                    "abstract_chinese": result.get("abstract_chinese", ""),
                    "phenotype_description": result.get(
                        "phenotype_description", "不涉及基因组编辑"
                    ),
                }
                writer.writerow(row)

        logger.info(f"符合要求的论文已单独导出到: {editing_papers_csv_file}")
    else:
        logger.warning("未找到涉及 UTR/uORF 基因组编辑的论文")

    # 导出详细分析结果
    detailed_csv_fields = [
        "pmid",
        "title",
        "journal",
        "year",
        "doi",
        "authors",
        "is_genome_editing",
        "editing_targets",
        "editing_methods",
        "plant_species",
        "phenotype_description",
        "confidence",
        "reasoning",
    ]

    with open(detailed_csv_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=detailed_csv_fields)
        writer.writeheader()

        for result in analysis_results:
            row = {
                "pmid": result.get("pmid", ""),
                "title": result.get("title", ""),
                "journal": result.get("journal", ""),
                "year": result.get("year", ""),
                "doi": result.get("doi", ""),
                "authors": result.get("authors", ""),
                "is_genome_editing": result.get("is_genome_editing", False),
                "editing_targets": "; ".join(result.get("editing_targets", [])),
                "editing_methods": "; ".join(result.get("editing_methods", [])),
                "plant_species": "; ".join(result.get("plant_species", [])),
                "phenotype_description": result.get(
                    "phenotype_description", "不涉及基因组编辑"
                ),
                "confidence": result.get("confidence", 0.0),
                "reasoning": result.get("reasoning", ""),
            }
            writer.writerow(row)

    logger.info(f"详细分析结果已导出到 CSV: {detailed_csv_file}")

    # ==================== 统计信息 ====================
    logger.info("\n" + "=" * 80)
    logger.info("分析统计")
    logger.info("=" * 80)

    genome_editing_count = sum(
        1 for result in analysis_results if result.get("is_genome_editing", False)
    )

    logger.info(f"总论文数: {len(analysis_results)}")
    logger.info(f"涉及 UTR/uORF 基因组编辑的论文: {genome_editing_count}")
    logger.info(
        f"比例: {genome_editing_count / len(analysis_results) * 100:.1f}%"
        if analysis_results
        else "0%"
    )

    # 统计编辑方法
    editing_methods_counter: dict[str, int] = {}
    for result in analysis_results:
        if result.get("is_genome_editing", False):
            for method in result.get("editing_methods", []):
                editing_methods_counter[method] = (
                    editing_methods_counter.get(method, 0) + 1
                )

    if editing_methods_counter:
        logger.info("\n【使用的基因组编辑技术】")
        for method, count in sorted(
            editing_methods_counter.items(), key=lambda x: x[1], reverse=True
        ):
            logger.info(f"  {method}: {count} 篇")

    logger.info("\n" + "=" * 80)
    logger.info("处理完成！")
    logger.info("=" * 80)
    logger.info("\n输出文件：")
    logger.info(f"  1. 论文原始数据: {csv_file}")
    logger.info(f"  2. 所有论文分析结果 CSV: {final_csv_file}")
    logger.info(f"  3. 符合要求的论文 CSV (仅基因组编辑): {editing_papers_csv_file}")
    logger.info(f"  4. 详细分析结果 CSV: {detailed_csv_file}")
    logger.info(f"  5. 完整分析结果 JSON: {analysis_json_file}")
    logger.info(f"  6. LLM 分析缓存: {llm_analysis_cache_file}")


if __name__ == "__main__":
    asyncio.run(main())
