#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""qc_scope_server.py —— QC 体检·服务器侧摸底（只读，不改任何数据）"""
import hashlib
import json
import os
import sqlite3
import sys
from collections import Counter

D = "/root/gov_crawler/"
print("=== ① daily_crawl_config.json ===")
raw = open(D + "daily_crawl_config.json", "rb").read()
print("  md5:", hashlib.md5(raw).hexdigest()[:12], "| 字节:", len(raw))
cfg = json.loads(raw.decode("utf-8"))
cr = cfg["crawlers"] if isinstance(cfg, dict) and "crawlers" in cfg else cfg
print("  条目数:", len(cr), "| 顶层类型:", type(cfg).__name__)
print("  字段:", sorted(cr[0].keys()))

scripts = [c.get("script") for c in cr]
print("\n  script 为空:", sum(1 for s in scripts if not s))
print("  script 去重数:", len(set(s for s in scripts if s)))
dup = Counter((c.get("script"), json.dumps(c.get("args"), ensure_ascii=False)) for c in cr)
print("  (script,args) 完全重复:", sum(1 for k, v in dup.items() if v > 1),
      [k[0] for k, v in dup.items() if v > 1][:5])
miss = [c.get("script") for c in cr if c.get("script") and not os.path.exists(D + c["script"])]
print("  ⚠️ config 指向但磁盘没有的脚本:", len(miss), miss[:8])
print("  enabled=false:", sum(1 for c in cr if c.get("enabled") is False))
print("  args 非列表/异常:", sum(1 for c in cr if c.get("args") is not None and not isinstance(c.get("args"), list)))
print("  args 含未知开关:", sum(1 for c in cr for a in (c.get("args") or [])
                              if isinstance(a, str) and not a.startswith("--") and not a.startswith("-")))
print("  group 分布 top6:", Counter(c.get("group") for c in cr).most_common(6))
print("  sync_mode 分布:", Counter(c.get("sync_mode") for c in cr).most_common())
disk = {f for f in os.listdir(D) if f.startswith("crawl_") and f.endswith(".py")}
print("\n  磁盘 crawl_*.py:", len(disk))
print("  ⚠️ 磁盘有但 config 没有（孤儿，永不更新）:", len(disk - set(scripts)))

print("\n=== ② gov_raw × script_name ===")
db = sqlite3.connect("file:/root/search.db?mode=ro", uri=True, timeout=30)
db.execute("PRAGMA busy_timeout=30000")
n = db.execute("SELECT COUNT(*) FROM gov_raw").fetchone()[0]
empty = db.execute("SELECT COUNT(*) FROM gov_raw WHERE script_name IS NULL OR TRIM(script_name)=''").fetchone()[0]
print("  总行数: %d | script_name 空: %d (%.2f%%)" % (n, empty, 100.0 * empty / n))
print("  inserted_at 空: %d (%.1f%%)" % (
    db.execute("SELECT COUNT(*) FROM gov_raw WHERE inserted_at IS NULL OR TRIM(inserted_at)=''").fetchone()[0],
    100.0 * db.execute("SELECT COUNT(*) FROM gov_raw WHERE inserted_at IS NULL OR TRIM(inserted_at)=''").fetchone()[0] / n))
print("  publish_date 空: %d | 单位数月(2026-9-9 型): %d | 未来日期: %d" % (
    db.execute("SELECT COUNT(*) FROM gov_raw WHERE publish_date IS NULL OR TRIM(publish_date)=''").fetchone()[0],
    db.execute("SELECT COUNT(*) FROM gov_raw WHERE publish_date LIKE '____-_-_%'").fetchone()[0],
    db.execute("SELECT COUNT(*) FROM gov_raw WHERE publish_date > date('now','+1 day')").fetchone()[0]))

rows = list(db.execute("SELECT script_name, COUNT(*), MAX(publish_date), "
                       "SUM(CASE WHEN attachments IS NULL OR attachments='' THEN 1 ELSE 0 END) "
                       "FROM gov_raw WHERE script_name IS NOT NULL AND TRIM(script_name)<>'' "
                       "GROUP BY script_name"))
print("  distinct script_name:", len(rows))
bad = [(s, c) for s, c, _, _ in rows if s and not os.path.exists(D + s)]
print("  ⚠️ 库内 script_name 磁盘查无此文件: %d 个（%d 行）%s" % (
    len(bad), sum(c for _, c in bad), [b[0] for b in bad[:6]]))

reg = set(s for s in scripts if s)
have = set(s for s, _, _, _ in rows)
print("\n=== ③ 注册脚本 vs 库内数据 ===")
print("  config 注册脚本: %d | 库内有数据的脚本: %d" % (len(reg), len(have)))
print("  ⚠️ 注册了但库里 0 行（空跑/从未入库）:", len(reg - have), sorted(reg - have)[:10])
stale = []
import datetime
today = datetime.date.today()
for s, c, mx, noatt in rows:
    if s not in reg:
        continue
    try:
        d = datetime.date(*[int(x) for x in (mx or "").split("-")[:3]])
        days = (today - d).days
    except Exception:
        days = -1
    stale.append((days, s, c, mx, noatt))
stale.sort(reverse=True)
print("\n  ⚠️ 最久未更新（注册脚本，按 MAX(publish_date)）top12:")
for days, s, c, mx, noatt in stale[:12]:
    print("     %5s 天 | %-42s | %6d 行 | 最新 %s" % (days if days >= 0 else "无日期", s[:42], c, mx))

zero_att = [(s, c) for s, c, mx, noatt in rows if c >= 30 and noatt == c]
print("\n  ⚠️ 行数≥30 且【全部】无附件的脚本: %d 个" % len(zero_att))
for s, c in sorted(zero_att, key=lambda x: -x[1])[:12]:
    print("     %-46s %5d 行" % (s[:46], c))

print("\n=== ④ FTS 一致性 ===")
gs = db.execute("SELECT COUNT(*) FROM gov_search").fetchone()[0]
print("  gov_raw: %d | gov_search: %d | 差: %d" % (n, gs, n - gs))
db.close()
