#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""fix_delete_wholesite_batch.py —— 批量去掉「整站 DELETE gov_raw/gov_search」

用法: python3 fix_delete_wholesite_batch.py [--apply] 脚本1 脚本2 ...
默认 dry-run。安全闸：
  * 必须含 INSERT OR IGNORE/REPLACE INTO gov_raw（幂等）否则跳过
  * 只注释「单行完整 execute 调用」形式的 DELETE 行，其它形态报告人工处理
  * 锚点必须唯一；ast 校验不过则不落盘；备份进 Archive/
"""
import ast
import os
import re
import shutil
import sys

D = "/root/gov_crawler/"
BAK = D + "Archive/"
TAG = "# QC20260925 去掉整站清空再重灌(抢锁+中途死掉会清空整站; page_url 有 UNIQUE 索引，插入本就幂等) "

DEL_RE = re.compile(
    r'^(\s*)((?:cur|c|conn|db|connection|today_conn)\.execute\(\s*)(["\'])'
    r'(DELETE\s+FROM\s+(?:gov_raw\s+WHERE\s+site_name|gov_search))',
    re.I)

args = [a for a in sys.argv[1:] if not a.startswith("--")]
APPLY = "--apply" in sys.argv
print("模式: %s | 目标 %d 个\n" % ("APPLY" if APPLY else "dry-run", len(args)))

for f in args:
    p = D + f
    print("─" * 84)
    if not os.path.exists(p):
        print("❌ 不存在: %s" % f); continue
    src = open(p, encoding="utf-8").read()
    if TAG in src:
        print("⚠️ 已修过，跳过: %s" % f); continue
    if not re.search(r"INSERT\s+OR\s+(REPLACE|IGNORE)\s+INTO\s+gov_raw", src, re.I):
        print("⛔ 非幂等插入，跳过: %s" % f); continue
    out, hits, bad = [], 0, 0
    for ln in src.split("\n"):
        if DEL_RE.match(ln) and ln.rstrip().endswith(")"):
            out.append(TAG + ln)
            hits += 1
        elif "DELETE FROM gov_raw WHERE site_name" in ln or "DELETE FROM gov_search" in ln:
            print("   ⚠️ 特殊形态(需人工): %s" % ln.strip()[:110]); bad += 1; out.append(ln)
        else:
            out.append(ln)
    src2 = "\n".join(out)
    # 加 busy_timeout（仅当存在单行 connect 且尚未设置）
    added = 0
    if "busy_timeout" not in src2:
        m = re.search(r'^(\s*)(\w+)\s*=\s*sqlite3\.connect\([^\n]*\)\s*$', src2, re.M)
        if m:
            ind, var, line = m.group(1), m.group(2), m.group(0)
            src2 = src2.replace(line, line + "\n%s%s.execute(\"PRAGMA busy_timeout=60000\")" % (ind, var), 1)
            added = 1
    print("   注释 DELETE %d 行 | 特殊形态 %d | 加 busy_timeout %s" % (hits, bad, "是" if added else "否"))
    if hits == 0:
        print("   ❌ 无可用锚点，跳过"); continue
    try:
        ast.parse(src2)
    except SyntaxError as e:
        print("   ❌ 语法错误，未落盘:", e); continue
    print("   残留 DELETE 行: %d" % len(re.findall(r"(?m)^(?!\s*#).*DELETE FROM (gov_raw WHERE site_name|gov_search)", src2)))
    if APPLY:
        os.makedirs(BAK, exist_ok=True)
        b = BAK + f + ".bak_20260925_delwholesite"
        if not os.path.exists(b):
            shutil.copy2(p, b)
        open(p, "w", encoding="utf-8").write(src2)
        print("   ✅ 已落盘 (备份 %s)" % os.path.basename(b))
    else:
        print("   🔸 dry-run 未落盘")
