"""检索策略结构化导出（PRISMA 附录可复现性）

将实际执行的 PubMed / Europe PMC 查询序列化为 PRISMA 兼容的检索策略文本。

主要功能：
1. `format_search_strategy()` — 将结构化策略数据格式化为 PRISMA 附录文本
2. `pubmed_syntax()` — 将 Europe PMC 语法转为 PubMed 语法

用法：
    formatted = format_search_strategy({
        "database": "PubMed",
        "date": "2026-06-15",
        "queries": [{"query": "...", "results": 200, "precision": "majr"}, ...],
        "filters": {"year_range": "2024:2026", "languages": ["en"]},
    }, language="en")
"""

import logging
from datetime import date
from typing import Any

logger = logging.getLogger(__name__)

# ─── Europe PMC ↔ PubMed 语法映射 ───

_FIELD_MAP_EUROPE_PMC_TO_PUBMED: dict[str, str] = {
    "TITLE": "[ti]",
    "ABSTRACT": "[ab]",
    "Title/Abstract": "[tiab]",
    "MeSH": "[MeSH]",
    "MAJR": "[MAJR]",
    "Author": "[au]",
    "Journal": "[ta]",
    "DOI": "[doi]",
    "PMCID": "[pmc]",
    "PUBMED": "[pmid]",
    "Year": "[dp]",
}

# 反向映射（PubMed → Europe PMC），供跨库导出
_FIELD_MAP_PUBMED_TO_EUROPE_PMC: dict[str, str] = {v: k for k, v in _FIELD_MAP_EUROPE_PMC_TO_PUBMED.items()}


def pubmed_syntax(europe_pmc_query: str) -> str:
    """将 Europe PMC 语法的查询字符串转换为标准 PubMed 语法。

    Europe PMC 用 TITLE/ABSTRACT，PubMed 用 [tiab]。
    此函数做字段限定符的机械替换，不改变布尔逻辑。

    Examples:
        "lung cancer[Title/Abstract]" → "lung cancer[tiab]"
        "("Lung Neoplasms"[MAJR]) AND 2024:2026[dp]" → unchanged (already PubMed)
    """
    result = europe_pmc_query
    for epmc_field, pubmed_field in _FIELD_MAP_EUROPE_PMC_TO_PUBMED.items():
        # 替换 field[EpMcLabel] 为 field[PubMedLabel]
        result = result.replace(f"[{epmc_field}]", pubmed_field)
        # 也处理大写的 [TITLE/ABSTRACT]
        if epmc_field != epmc_field.upper():
            result = result.replace(f"[{epmc_field.upper()}]", pubmed_field)
    return result


def europe_pmc_syntax(pubmed_query: str) -> str:
    """将 PubMed 语法转换为 Europe PMC 语法。"""
    result = pubmed_query
    for pubmed_field, epmc_field in _FIELD_MAP_PUBMED_TO_EUROPE_PMC.items():
        result = result.replace(pubmed_field, f"[{epmc_field}]")
    return result


# ─── 格式化输出 ───

def format_search_strategy(
    strategy: dict[str, Any] | None,
    language: str = "zh",
) -> str:
    """将结构化检索策略格式化为 PRISMA 附录可用文本。

    输入结构示例：
    {
        "database": "PubMed",
        "date": "2026-06-15",
        "queries": [
            {"query": '"Lung Neoplasms"[MAJR]', "results": 342, "precision": "majr"},
            {"query": '"lung cancer"[Title/Abstract]', "results": 581, "precision": "broad"},
        ],
        "filters": {"year_range": "2024:2026", "languages": ["en"]},
        "mesh_terms_used": ["Lung Neoplasms", "Breast Neoplasms", ...],
        "search_notes": "...",
    }
    """
    if not strategy or not strategy.get("queries"):
        return ""

    lines: list[str] = []
    db = strategy.get("database", "PubMed")
    search_date = strategy.get("date", date.today().isoformat())
    filters = strategy.get("filters", {})

    if language == "en":
        lines.append(f"# Search Strategy — {db}")
        lines.append(f"# Date: {search_date}")
        lines.append("")
        lines.append("## Database")
        lines.append(db)
        lines.append("")

        if filters.get("year_range"):
            lines.append(f"## Year Range\n{filters['year_range']}\n")
        if filters.get("languages"):
            lines.append(f"## Language Restriction\n{', '.join(filters['languages'])}\n")

        lines.append("## Search Queries")
        for i, q in enumerate(strategy.get("queries", []), 1):
            query_str = q.get("query", "")
            # 如果需要 PubMed 导出，做语法转换
            if q.get("target") == "pubmed":
                query_str = pubmed_syntax(query_str)
            results_str = f" — {q['results']} results" if q.get("results") else ""
            precision_label = {
                "majr": "[Precision: MeSH Major Topic]",
                "mesh": "[Precision: MeSH]",
                "broad": "[Precision: Title/Abstract]",
            }.get(q.get("precision", ""), "")
            lines.append(f"\n  #{i} {precision_label}".strip())
            lines.append(f"  {query_str}{results_str}")

    else:
        lines.append(f"# 检索策略 — {db}")
        lines.append(f"# 检索日期: {search_date}")
        lines.append("")
        lines.append("## 数据库")
        lines.append(db)
        lines.append("")

        if filters.get("year_range"):
            lines.append(f"## 年份范围\n{filters['year_range']}\n")
        if filters.get("languages"):
            lines.append(f"## 语种限制\n{', '.join(filters['languages'])}\n")

        lines.append("## 检索式")
        for i, q in enumerate(strategy.get("queries", []), 1):
            query_str = q.get("query", "")
            if q.get("target") == "pubmed":
                query_str = pubmed_syntax(query_str)
            results_str = f" — {q['results']} 篇" if q.get("results") else ""
            precision_label = {
                "majr": "[精度: MeSH Major Topic]",
                "mesh": "[精度: MeSH]",
                "broad": "[精度: 标题/摘要]",
            }.get(q.get("precision", ""), "")
            lines.append(f"\n  #{i} {precision_label}".strip())
            lines.append(f"  {query_str}{results_str}")

    if strategy.get("mesh_terms_used"):
        lines.append("")
        if language == "en":
            lines.append("## MeSH Terms Used\n" + "; ".join(strategy["mesh_terms_used"]))
        else:
            lines.append("## 使用的 MeSH 词\n" + "; ".join(strategy["mesh_terms_used"]))

    if strategy.get("search_notes"):
        lines.append("")
        if language == "en":
            lines.append(f"## Notes\n{strategy['search_notes']}")
        else:
            lines.append(f"## 备注\n{strategy['search_notes']}")

    return "\n".join(lines)
