"""文献打标服务：mesh_headings → global_tags → global_literature_tags

策略：
1. 按 mesh_ui 精确匹配（存量种子标签 + 懒创建标签）
2. 按 name_en 回退匹配（import_mesh_tags.py 导入的 C04 标签无 mesh_ui）
3. 仍未匹配 → 懒创建标签（确保打标覆盖）
"""

import uuid
import logging

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.literature import GlobalTag, GlobalLiteratureTag, GlobalTagTreeNumber

logger = logging.getLogger(__name__)

# 新标签默认分类（按 mesh_ui 前缀推断）
_CATEGORY_MAP = {
    "C": "cancer", "D": "gene", "E": "treatment",
    "F": "mesh_other", "G": "mesh_other", "H": "mesh_other",
    "I": "mesh_other", "J": "mesh_other", "K": "mesh_other",
    "L": "mesh_other", "M": "mesh_other", "N": "mesh_other",
    "V": "study_type", "Z": "mesh_other",
}


async def tag_article(db: AsyncSession, lit_id: uuid.UUID,
                      mesh_headings: list[dict]) -> int:
    """为一篇文献打标

    返回本次新增的标签关联数。
    """
    if not mesh_headings:
        return 0

    mesh_uis = [mh["ui"] for mh in mesh_headings if mh.get("ui")]
    if not mesh_uis:
        return 0

    # 1. 按 mesh_ui 批量查找
    result = await db.execute(
        select(GlobalTag).where(GlobalTag.mesh_ui.in_(mesh_uis))
    )
    matched: list[GlobalTag] = list(result.scalars().all())

    # 2. 按 name_en 匹配 C04 导入标签（无 mesh_ui）
    # 对 ALL headings 都尝试 name_en 匹配——已通过 mesh_ui 匹配的 heading
    # 如果同时有 C04 导入标签（无 mesh_ui），也一并关联
    all_names = [
        mh["descriptor"] for mh in mesh_headings if mh.get("descriptor")
    ]
    if all_names:
        result = await db.execute(
            select(GlobalTag).where(GlobalTag.name_en.in_(all_names))
        )
        name_matched = list(result.scalars().all())
        already_matched_ids = {t.id for t in matched}
        for t in name_matched:
            if t.id not in already_matched_ids:
                matched.append(t)

    # 3. 仍未匹配的 → 懒创建
    matched_uis = {t.mesh_ui for t in matched if t.mesh_ui}
    created_tags: list[GlobalTag] = []
    for mh in mesh_headings:
        ui = mh.get("ui")
        if not ui or ui in matched_uis:
            continue
        tag = GlobalTag(
            mesh_ui=ui,
            name_en=mh.get("descriptor", ""),
            name_zh=None,            # 懒创建无中文名，后台补充
            path=mh.get("descriptor", ""),
            tag_category=_guess_category(mh.get("ui", "")),
            level=1,
            is_selectable=True,
            source="auto",           # 标注为待审核来源
            is_active=False,         # 未审核，用户端不可见
        )
        db.add(tag)
        await db.flush()
        matched.append(tag)
        matched_uis.add(ui)
        created_tags.append(tag)
        logger.debug("懒创建标签: %s (%s)", tag.name_en, tag.mesh_ui)

    if not matched:
        return 0

    # 4. 批量查询已有关系
    result = await db.execute(
        select(GlobalLiteratureTag.tag_id).where(
            GlobalLiteratureTag.literature_id == lit_id,
            GlobalLiteratureTag.tag_id.in_([t.id for t in matched]),
        )
    )
    existing_tag_ids = {r for (r,) in result.all()}

    # 5. 建立关联
    count = 0
    for tag in matched:
        if tag.id in existing_tag_ids:
            continue
        is_major = any(
            mh.get("ui") == tag.mesh_ui and mh.get("major")
            for mh in mesh_headings
        )
        db.add(GlobalLiteratureTag(
            literature_id=lit_id,
            tag_id=tag.id,
            is_major=is_major,
        ))
        tag.article_count += 1
        count += 1

    return count


async def retag_all_unindexed(db: AsyncSession, batch_size: int = 500) -> int:
    """回填所有有 mesh_headings 但无 global_literature_tags 的文献

    返回处理的文献数。
    """
    from app.models.literature import GlobalLiterature

    total = 0
    while True:
        result = await db.execute(
            select(GlobalLiterature).where(
                GlobalLiterature.mesh_headings.isnot(None),
                ~GlobalLiterature.id.in_(
                    select(GlobalLiteratureTag.literature_id).distinct()
                ),
            ).limit(batch_size)
        )
        rows = result.scalars().all()
        if not rows:
            break
        for lit in rows:
            mh = lit.mesh_headings or []
            await tag_article(db, lit.id, mh)
        await db.commit()
        total += len(rows)
        logger.info("retag 进度: %d 篇", total)
    return total


def _guess_category(mesh_ui: str) -> str:
    """从 mesh_ui（D008175）推断分类"""
    prefix = mesh_ui[0] if mesh_ui else ""
    return _CATEGORY_MAP.get(prefix, "mesh_other")
