"""GlobalJournal 种子化：从 global_literature 提取所有不重复期刊

从现有数据自动提取期刊并写入 global_journals 表。
- 有 ISSN 的记录按 ISSN 分组，取出现频率最高的 journal 名称作为 canonical name
- 无 ISSN 的记录按 journal 名称聚合
- 已有 curated 记录（is_active=True）保留原有 tier 不动
- 新增记录默认 tier=4、is_active=True
- 自动计算 priority_score 和 specialty
"""

import os
import sys
import uuid as _uuid
from collections import Counter
from datetime import datetime

from sqlalchemy import create_engine, text, select, func, String
from sqlalchemy.orm import Session

# ── 数据库连接 ──
_DEFAULT_URL = "postgresql://scilit:scilit_dev@localhost:5432/scilit"

def _get_engine():
    url = os.environ.get("SEED_DB_URL") or _DEFAULT_URL
    return create_engine(url, pool_pre_ping=True)


def _score(tier: str, impact_factor: float | None, article_count: int, specialty: str | None) -> float:
    """内联版评分，避免依赖 app.services.journal_utils（独立脚本）"""
    tier_base = {"1": 80, "2": 65, "3": 50}.get(tier, 20)
    if_bonus = 0
    if impact_factor is not None:
        if impact_factor >= 20: if_bonus = 15
        elif impact_factor >= 10: if_bonus = 10
        elif impact_factor >= 5: if_bonus = 5
        elif impact_factor >= 2: if_bonus = 2
    count_bonus = 0
    if article_count >= 5000: count_bonus = 10
    elif article_count >= 1000: count_bonus = 5
    elif article_count >= 100: count_bonus = 2
    specialty_bonus = 10 if specialty == "oncology" else 0
    return min(tier_base + if_bonus + count_bonus + specialty_bonus, 100.0)


def _spec(tier: str, name: str | None) -> str | None:
    """内联版专科判定"""
    if tier in ("1", "2", "3"):
        return "oncology"
    if name:
        nl = name.lower()
        for kw in ("oncol", "cancer", "tumor", "tumour", "neoplas"):
            if kw in nl:
                return "oncology"
    return None


def seed_journals(dry_run: bool = False):
    """主流程"""
    with Session(_get_engine()) as db:
        # 1. 已有的 GlobalJournal 记录
        existing = db.execute(
            select(text("id, issn, eissn, name, tier, is_active"))
            .select_from(text("global_journals"))
        ).all()
        existing_by_issn: dict[str, dict] = {}
        for row in existing:
            if row.issn:
                existing_by_issn[row.issn] = {
                    "id": row.id, "name": row.name, "tier": row.tier or "4",
                    "is_active": row.is_active,
                }
            if row.eissn:
                existing_by_issn[row.eissn] = {
                    "id": row.id, "name": row.name, "tier": row.tier or "4",
                    "is_active": row.is_active,
                }
        print(f"已有 GlobalJournal 记录: {len(existing)} 条")

        # 2. 从 global_literature 提取期刊
        rows = db.execute(
            text("SELECT journal, journal_issn FROM global_literature WHERE journal IS NOT NULL AND journal != ''")
        ).all()
        print(f"global_literature 有期刊名称的记录: {len(rows)} 条")

        # 按 ISSN 分组统计 journal 名称频次
        issn_groups: dict[str, Counter] = {}       # issn → Counter(journal_name)
        no_issn_counter: Counter = Counter()        # 无 ISSN 的 journal 名称
        issn_journal_map: dict[str, str] = {}       # issn → 最常见 journal name

        for journal, issn in rows:
            if issn:
                issn = issn.strip()
                if issn not in issn_groups:
                    issn_groups[issn] = Counter()
                issn_groups[issn][journal.strip()] += 1
            else:
                no_issn_counter[journal.strip()] += 1

        # 计算每 ISSN 最常见的名称
        for issn, counter in issn_groups.items():
            issn_journal_map[issn] = counter.most_common(1)[0][0]

        # 3. 决定哪些需要插入/更新
        to_insert = []  # (issn, name, article_count, publisher)
        to_update_count = []
        total_new = 0
        total_existing = 0

        # 有 ISSN 的记录
        for issn, name in issn_journal_map.items():
            article_count = issn_groups[issn].total()
            if issn in existing_by_issn:
                total_existing += 1
                to_update_count.append((article_count, issn))
            else:
                # 跨 ISSN 去重：检查是否有名称高度相似（trigram > 0.9）的已有期刊
                merged = False
                try:
                    sim_check = db.execute(
                        text("""
                            SELECT id, name, issn, eissn FROM global_journals
                            WHERE issn IS NOT NULL AND issn != :issn
                              AND similarity(name, :name) > 0.9
                            LIMIT 1
                        """),
                        {"issn": issn, "name": name},
                    ).fetchone()
                    if sim_check:
                        # 名称高度相似 → 视为同刊，将新 ISSN 并入 eissn
                        target_eissn = sim_check.eissn or ""
                        new_eissn = issn if not target_eissn else target_eissn
                        db.execute(
                            text("""
                                UPDATE global_journals
                                SET eissn = :eissn, article_count = article_count + :cnt,
                                    updated_at = NOW()
                                WHERE id = :id
                            """),
                            {"eissn": new_eissn, "cnt": article_count, "id": sim_check.id},
                        )
                        print(f"  ↳ 跨 ISSN 合并: {name[:50]} ({issn}) → {sim_check.name[:50]} ({sim_check.issn})")
                        total_existing += 1
                        merged = True
                except Exception:
                    pass  # pg_trgm 可能未安装

                if not merged:
                    total_new += 1
                specialty = _spec("4", name)
                priority_score = _score("4", None, article_count, specialty)
                to_insert.append({
                    "id": str(_uuid.uuid4()),
                    "name": name[:500],
                    "issn": issn,
                    "eissn": None,
                    "tier": "4",
                    "impact_factor": None,
                    "publisher": None,
                    "article_count": article_count,
                    "is_active": True,
                    "priority_score": priority_score,
                    "priority_source": "auto",
                    "specialty": specialty,
                })

        # 无 ISSN 的记录（按名称聚合，article_count >= 3 才收录以避免垃圾）
        no_issn_new = 0
        for name, count in no_issn_counter.most_common():
            if count < 3:
                continue
            # 检查是否已存在同名记录
            exists = db.execute(
                text("SELECT 1 FROM global_journals WHERE name = :name AND issn IS NULL LIMIT 1"),
                {"name": name},
            ).scalar()
            if exists:
                db.execute(
                    text("UPDATE global_journals SET article_count = article_count + :cnt WHERE name = :name AND issn IS NULL"),
                    {"cnt": count, "name": name},
                )
                continue
            to_insert.append({
                "id": str(_uuid.uuid4()),
                "name": name[:500],
                "issn": None,
                "eissn": None,
                "tier": "4",
                "impact_factor": None,
                "publisher": None,
                "article_count": count,
                "is_active": True,
                "priority_score": _score("4", None, count, _spec("4", name)),
                "priority_source": "auto",
                "specialty": _spec("4", name),
            })
            no_issn_new += 1

        print(f"\n统计:")
        print(f"  已有 ISSN 匹配（更新 article_count）: {total_existing}")
        print(f"  新 ISSN 期刊: {total_new}")
        print(f"  无 ISSN 新期刊: {no_issn_new}")
        print(f"  总计待插入: {len(to_insert)}")

        if dry_run:
            print("\n[Dry Run] 不执行写入。")
            return

        # 提交 Session 事务，释放表锁，避免与下面 raw_connection 的 INSERT 冲突
        db.commit()

        # 4. 批量插入
        if to_insert:
            now_val = datetime.utcnow()
            conn = _get_engine().raw_connection()
            try:
                with conn.cursor() as cur:
                    import psycopg2.extras
                    psycopg2.extras.execute_values(
                        cur,
                        """INSERT INTO global_journals (id, name, issn, eissn, tier, impact_factor, publisher, article_count, is_active, priority_score, priority_source, specialty, created_at, updated_at)
                           VALUES %s
                           ON CONFLICT DO NOTHING""",
                        [(
                            r["id"], r["name"][:500], r["issn"], r["eissn"],
                            r["tier"], r["impact_factor"], r["publisher"],
                            r["article_count"], r["is_active"],
                            r["priority_score"], r["priority_source"], r["specialty"],
                            now_val, now_val,
                        ) for r in to_insert],
                        template="(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
                    )
                conn.commit()
            finally:
                conn.close()
            print(f"\n插入 {len(to_insert)} 条记录。")

        # 5. 更新已有记录的 article_count
        for cnt, issn in to_update_count:
            db.execute(
                text("UPDATE global_journals SET article_count = :cnt WHERE issn = :issn"),
                {"cnt": cnt, "issn": issn},
            )
        db.commit()
        print(f"更新 {len(to_update_count)} 条已有记录的 article_count。")

        # 6. 最终统计
        final_count = db.execute(text("SELECT COUNT(*) FROM global_journals")).scalar()
        print(f"\n完成！global_journals 总记录数: {final_count}")


if __name__ == "__main__":
    dry = "--dry-run" in sys.argv
    seed_journals(dry_run=dry)
