"""
导入完整性验证脚本
检查 DOCX 文件数 vs 数据库入库数，定位漏读/漏写的药品
"""
import os, sys, json, asyncio
from pathlib import Path
from collections import Counter

# 添加同目录模块
sys.path.insert(0, str(Path(__file__).resolve().parent))
from docx_ingest import find_docx_files, parse_docx

# 数据库
import asyncpg

SOURCE_DIR = os.environ.get("DOCX_SOURCE_DIR", "/opt/2025")
DB_HOST = os.environ.get("POSTGRES_HOST", "localhost")
DB_PORT = os.environ.get("POSTGRES_PORT", "5432")
DB_NAME = os.environ.get("POSTGRES_DB", "pharmacopoeia")
DB_USER = os.environ.get("POSTGRES_USER", "postgres")
DB_PASSWORD = os.environ.get("POSTGRES_PASSWORD", "postgres")


async def main():
    # ==========================================
    # 1. 扫描 DOCX 文件
    # ==========================================
    print("=" * 60)
    print("📂 扫描 DOCX 文件...")
    files = find_docx_files(SOURCE_DIR)
    print(f"   DOCX 文件总数: {len(files)}")

    # 提取文件名（去 .docx）作为药品名
    docx_names = set()
    docx_by_volume = Counter()
    for fp in files:
        name = Path(fp).stem
        docx_names.add(name)
        vol = "一部"
        for k in ["output4", "output3", "output2", "output"]:
            if k in fp:
                vol = {"output": "一部", "output2": "二部", "output3": "三部", "output4": "四部"}[k]
                break
        docx_by_volume[vol] += 1
    print(f"   去重后唯一药名: {len(docx_names)}")
    print(f"   各卷分布: {dict(docx_by_volume)}")

    # ==========================================
    # 2. 查询数据库
    # ==========================================
    print("\n📊 查询数据库...")
    conn = await asyncpg.connect(
        host=DB_HOST, port=DB_PORT, database=DB_NAME,
        user=DB_USER, password=DB_PASSWORD
    )

    # 2.1 药品统计
    total_drugs = await conn.fetchval("SELECT COUNT(*) FROM drugs WHERE is_active = TRUE")
    total_chunks = await conn.fetchval("SELECT COUNT(*) FROM drug_chunks WHERE vec IS NOT NULL")
    total_chunks_null = await conn.fetchval("SELECT COUNT(*) FROM drug_chunks WHERE vec IS NULL")

    print(f"   drugs 表 (active): {total_drugs}")
    print(f"   drug_chunks (有向量): {total_chunks}")
    print(f"   drug_chunks (无向量): {total_chunks_null}")

    # 2.2 获取数据库中所有药名
    db_names = set()
    rows = await conn.fetch("SELECT name FROM drugs WHERE is_active = TRUE")
    for r in rows:
        db_names.add(r["name"])
    print(f"   数据库中药名: {len(db_names)}")

    # 2.3 按来源版本统计
    version_counts = await conn.fetch("""
        SELECT source_version, COUNT(*) FROM drugs
        WHERE is_active = TRUE GROUP BY source_version ORDER BY COUNT(*) DESC
    """)
    print(f"   版本分布:")
    for r in version_counts:
        print(f"     {r['source_version']}: {r['count']}")

    # 2.4 按分类统计
    cat_counts = await conn.fetch("""
        SELECT category, COUNT(*) FROM drugs
        WHERE is_active = TRUE GROUP BY category ORDER BY COUNT(*) DESC
    """)
    print(f"   分类分布:")
    for r in cat_counts:
        print(f"     {r['category']}: {r['count']}")

    # ==========================================
    # 3. 对比分析
    # ==========================================
    print("\n🔍 对比分析:")

    # 3.1 DOCX 有但 DB 没有的（漏读）
    missing = docx_names - db_names
    if missing:
        print(f"\n   ❌ DOCX 有但数据库没有（{len(missing)} 个）:")
        for name in sorted(missing)[:30]:
            print(f"      - {name}")
        if len(missing) > 30:
            print(f"      ... 还有 {len(missing) - 30} 个")
    else:
        print(f"\n   ✅ 无漏读：所有 DOCX 药名均已在数据库中")

    # 3.2 DB 有但 DOCX 没有的（额外数据，如 Wiki）
    extra = db_names - docx_names
    if extra:
        print(f"\n   📝 数据库额外药名（Wiki/样本数据，{len(extra)} 个）:")
        for name in sorted(extra):
            print(f"      - {name}")

    # ==========================================
    # 4. 抽查特定药品的 sections
    # ==========================================
    print("\n🔬 抽查药品内容完整性:")
    spot_check = ["布洛芬", "甲硝唑", "阿莫西林", "对乙酰氨基酚", "二甲双胍"]
    for name in spot_check:
        drug = await conn.fetchrow(
            "SELECT drug_id, name, sections, source_version FROM drugs WHERE name = $1 AND is_active = TRUE",
            name
        )
        if drug:
            sections = json.loads(drug["sections"]) if drug["sections"] else {}
            chunk_count = await conn.fetchval(
                "SELECT COUNT(*) FROM drug_chunks WHERE drug_id = $1 AND vec IS NOT NULL",
                drug["drug_id"]
            )
            sec_names = list(sections.keys())
            print(f"   ✅ {name} | {len(sec_names)} sections | {chunk_count} chunks | {drug['source_version']}")
            print(f"      栏目: {sec_names[:10]}...")
        else:
            print(f"   ❌ {name}: 数据库中不存在")

    # ==========================================
    # 5. 检查 chunks 完整性
    # ==========================================
    print("\n📐 Chunks 完整性检查:")

    # 5.1 检查 drug_id 引用完整性（孤儿 chunk）
    orphan_chunks = await conn.fetchval("""
        SELECT COUNT(*) FROM drug_chunks c
        LEFT JOIN drugs d ON d.drug_id = c.drug_id
        WHERE d.id IS NULL
    """)
    print(f"   孤儿 chunks（无对应 drug）: {orphan_chunks}")

    # 5.2 有 drug 但没有 chunk 的
    no_chunk_drugs = await conn.fetchval("""
        SELECT COUNT(*) FROM drugs d
        WHERE d.is_active = TRUE
        AND NOT EXISTS (SELECT 1 FROM drug_chunks c WHERE c.drug_id = d.drug_id)
    """)
    print(f"   无 chunk 的药品: {no_chunk_drugs}")

    # 5.3 vec 维度是否正确
    vec_dim = await conn.fetchval("""
        SELECT vector_dims(vec) FROM drug_chunks WHERE vec IS NOT NULL LIMIT 1
    """)
    print(f"   向量维度: {vec_dim}")

    # ==========================================
    # 6. 汇总结论
    # ==========================================
    print("\n" + "=" * 60)
    print("📋 验证结论:")
    print(f"   DOCX 文件: {len(files)}")
    print(f"   数据库中药品: {total_drugs}")
    print(f"   数据库 chunks: {total_chunks}")
    print(f"   漏读药品: {len(missing)}")
    print(f"   额外药品 (Wiki等): {len(extra)}")
    print(f"   孤儿 chunks: {orphan_chunks}")
    print(f"   无 chunk 药品: {no_chunk_drugs}")
    if len(missing) == 0 and orphan_chunks == 0 and total_chunks > 0:
        print("\n   ✅ 导入完整，无漏读漏写")
    else:
        print(f"\n   ⚠️  发现问题，请检查上述 ❌ 项")
    print("=" * 60)

    await conn.close()


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