"""一次性数据清洗：设置 source / is_active，合并重复标签

用法:
  PYTHONPATH=. python scripts/cleanup_tags.py --mode dry-run   # 预览
  PYTHONPATH=. python scripts/cleanup_tags.py --mode apply     # 实际执行
"""

import argparse
import asyncio
import json
import os
import sys
from pathlib import Path

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
os.environ.setdefault("SPECIALTY", "oncology")

from sqlalchemy import select, func, and_
from app.db import async_session
from app.models.literature import GlobalTag, GlobalTagTreeNumber, GlobalLiteratureTag

# 种子标签路径列表（从 seed_oncology_tags.json 提取）
SEED_PATHS = set()
_seed_paths_file = Path(__file__).parent / "seed_oncology_tags.json"
if _seed_paths_file.exists():
    with open(_seed_paths_file, encoding="utf-8") as f:
        for entry in json.load(f):
            SEED_PATHS.add(entry["path"])

# 已知的种子 mesh_ui → C04 MeSH 描述词名称映射（用于合并重复）
# 种子用口语名（Lung Cancer），C04 用 NLM 标准名（Lung Neoplasms）
MESH_UI_TO_C04_NAME = {
    "D008175": "Lung Neoplasms",       # Lung Cancer
    "D001943": "Breast Neoplasms",     # Breast Cancer
    "D015179": "Colorectal Neoplasms", # Colorectal Cancer
    "D013274": "Stomach Neoplasms",    # Gastric Cancer
    "D008113": "Liver Neoplasms",      # Liver Cancer
    "D010190": "Pancreatic Neoplasms", # Pancreatic Cancer
    "D011471": "Prostatic Neoplasms",  # Prostate Cancer
    "D004938": "Esophageal Neoplasms", # Esophageal Cancer
    "D010051": "Ovarian Neoplasms",    # Ovarian Cancer
    "D002583": "Uterine Cervical Neoplasms",  # Cervical Cancer
    "D006258": "Head and Neck Neoplasms",     # Head and Neck Cancer
    "D009303": "Nasopharyngeal Neoplasms",    # Nasopharyngeal Carcinoma
    "D001932": "Brain Neoplasms",      # Brain Tumor
    "D005909": "Glioblastoma",         # GBM
    "D007680": "Kidney Neoplasms",     # Kidney Cancer (same name)
    "D001749": "Urinary Bladder Neoplasms",   # Bladder Cancer
    "D013964": "Thyroid Neoplasms",    # Thyroid Cancer
    "D012878": "Skin Neoplasms",       # Skin Cancer
    "D005910": "Glioma",               # Glioma (same name)
    "D002292": "Carcinoma, Renal Cell",# Renal Cell Carcinoma
    "D002289": "Carcinoma, Non-Small-Cell Lung",  # NSCLC
    "D055752": "Small Cell Lung Carcinoma",       # SCLC
    "D006528": "Carcinoma, Hepatocellular",       # HCC
    "D009101": "Multiple Myeloma",     # same name
    "D007938": "Leukemia",            # same name
    "D008223": "Lymphoma",            # same name
    "D008545": "Melanoma",            # same name
    "D000970": "Antineoplastic Agents",
    "D058990": "Molecular Targeted Therapy",
    "D007167": "Immunotherapy",
    "D000971": "Drug Therapy",         # Chemotherapy
    "D011878": "Radiotherapy",
    "D013511": "Surgical Procedures, Operative",  # Surgery
    "D017410": "Practice Guideline",   # Clinical Guideline
    "D016032": "Randomized Controlled Trial",
    "D017326": "Clinical Trial, Phase III",
    "D015201": "Meta-Analysis",
    "D020360": "Neoadjuvant Therapy",
    "D009362": "Neoplasm Metastasis",
    "D009364": "Neoplasm Recurrence, Local",
    "D055088": "Early Detection of Cancer",
    "D014408": "Biomarkers",
    "D019008": "Drug Resistance, Neoplasm",
    "D059016": "Tumor Microenvironment",
    "D063646": "Carcinogenesis",
    "D047428": "Protein Kinase Inhibitors",
}


async def dry_run():
    async with async_session() as db:
        all_tags = (await db.execute(select(GlobalTag).order_by(GlobalTag.path))).scalars().all()
        all_tree_tag_ids = set(
            (await db.execute(select(GlobalTagTreeNumber.tag_id).distinct())).scalars().all()
        )
        total = len(all_tags)
        manual, mesh, auto = 0, 0, 0
        active, inactive = 0, 0
        duplicates = []

        for tag in all_tags:
            is_seed = tag.path in SEED_PATHS
            is_mesh_tag = tag.id in all_tree_tag_ids
            has_tree = bool(
                (await db.execute(
                    select(func.count(GlobalTagTreeNumber.id)).where(GlobalTagTreeNumber.tag_id == tag.id)
                )).scalar()
            )
            s = "manual" if is_seed else ("mesh" if has_tree else "auto")
            a = s in ("manual", "mesh")
            if s == "manual":
                manual += 1
            elif s == "mesh":
                mesh += 1
            else:
                auto += 1
            if a:
                active += 1
            else:
                inactive += 1

            # 检测重复：种子有 mesh_ui，C04 有同名
            if is_seed and tag.mesh_ui and tag.mesh_ui in MESH_UI_TO_C04_NAME:
                c04_name = MESH_UI_TO_C04_NAME[tag.mesh_ui]
                dup = await db.execute(
                    select(GlobalTag).where(
                        and_(
                            GlobalTag.name_en.ilike(c04_name),
                            GlobalTag.id != tag.id,
                        )
                    )
                )
                dup_tag = dup.scalar()
                if dup_tag:
                    duplicates.append((tag, dup_tag))

        print(f"=== 清洗预览 ===")
        print(f"标签总数: {total}")
        print(f"  source=manual: {manual}")
        print(f"  source=mesh:   {mesh}")
        print(f"  source=auto:   {auto}")
        print(f"  is_active=True:  {active}")
        print(f"  is_active=False: {inactive}")
        if duplicates:
            print(f"\n检测到 {len(duplicates)} 个重复对:")
            for seed, dup in duplicates:
                lit_cnt = await db.scalar(
                    select(func.count(GlobalLiteratureTag.literature_id))
                    .where(GlobalLiteratureTag.tag_id == dup.id)
                )
                print(f"  种子: {seed.name_zh}/{seed.name_en} ({seed.mesh_ui})")
                print(f"  重复: {dup.name_en} (路径: {dup.path}, {lit_cnt} 篇文献)")
        else:
            print(f"\n未检测到重复标签（C04 可能尚未导入）")


async def apply():
    async with async_session() as db:
        all_tags = (await db.execute(select(GlobalTag).order_by(GlobalTag.path))).scalars().all()

        manual_ids = set()
        mesh_ids = set()
        auto_ids = set()

        for tag in all_tags:
            is_seed = tag.path in SEED_PATHS
            has_tree = bool(
                (await db.execute(
                    select(func.count(GlobalTagTreeNumber.id)).where(GlobalTagTreeNumber.tag_id == tag.id)
                )).scalar()
            )

            if is_seed:
                tag.source = "manual"
                tag.is_active = True
                manual_ids.add(tag.id)
            elif has_tree:
                tag.source = "mesh"
                tag.is_active = True
                mesh_ids.add(tag.id)
            else:
                tag.source = "auto"
                tag.is_active = False
                auto_ids.add(tag.id)

        await db.commit()
        print(f"source/is_active 设置完成: manual={len(manual_ids)}, mesh={len(mesh_ids)}, auto={len(auto_ids)}")

        # 合并重复标签（种子 mesh_ui → C04 同义词）
        merged = 0
        for tag in all_tags:
            if tag.id not in manual_ids or not tag.mesh_ui or tag.mesh_ui not in MESH_UI_TO_C04_NAME:
                continue
            c04_name = MESH_UI_TO_C04_NAME[tag.mesh_ui]
            dup = await db.execute(
                select(GlobalTag).where(
                    and_(
                        GlobalTag.name_en.ilike(c04_name),
                        GlobalTag.id != tag.id,
                    )
                )
            )
            dup_tag = dup.scalar()
            if not dup_tag:
                continue

            # 把重复标签的文献关联移到种子标签
            dup_lits = await db.execute(
                select(GlobalLiteratureTag).where(GlobalLiteratureTag.tag_id == dup_tag.id)
            )
            moved = 0
            for glt in dup_lits.scalars():
                existing = await db.execute(
                    select(GlobalLiteratureTag).where(
                        and_(
                            GlobalLiteratureTag.literature_id == glt.literature_id,
                            GlobalLiteratureTag.tag_id == tag.id,
                        )
                    )
                )
                if not existing.scalar():
                    db.add(GlobalLiteratureTag(
                        literature_id=glt.literature_id,
                        tag_id=tag.id,
                        is_major=glt.is_major,
                    ))
                    moved += 1
                await db.delete(glt)

            # 删除重复标签
            await db.delete(dup_tag)
            merged += 1
            print(f"  合并: {tag.name_zh}/{tag.name_en} ← {dup_tag.name_en} (移动 {moved} 篇)")

        await db.commit()
        print(f"\n完成! 合并 {merged} 个重复标签")

        # 刷新 article_count（全量）
        print("刷新 article_count...")
        all_tags2 = (await db.execute(select(GlobalTag))).scalars().all()
        for tag in all_tags2:
            cnt = await db.scalar(
                select(func.count(GlobalLiteratureTag.literature_id))
                .where(GlobalLiteratureTag.tag_id == tag.id)
            )
            tag.article_count = cnt or 0
        await db.commit()
        print("article_count 刷新完成")


async def main():
    parser = argparse.ArgumentParser(description="标签数据清洗")
    parser.add_argument("--mode", choices=["dry-run", "apply"], default="dry-run")
    args = parser.parse_args()
    if args.mode == "dry-run":
        await dry_run()
    else:
        await apply()


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