#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""更安全的批量修法：在手动 gov_search 插入之前补一行 conn.commit()。

原理：原脚本 gov_raw 插入 → 手动 FTS 插入 → commit。FTS 那条因触发器已写过同一
rowid 而 IntegrityError → 异常被吞 → **gov_raw 那条因未 commit 一并回滚** = 静默丢数据。
在 FTS 之前先 commit，gov_raw 立即落盘，后续 FTS 失败也带不走它。
一行插入、不动语句结构 → 不会产生空 try 块之类的语法问题。
"""
import ast
import io
import os
import re
import shutil
import sys

D = "/root/gov_crawler"
ARCH = os.path.join(D, "Archive")
DRY = "--dry-run" in sys.argv

pat_gs = re.compile(r'^([ \t]*)(?:c|cur|conn\.cursor\(\)|c2)\.execute\(\s*["\']INSERT\s+(?:OR\s+REPLACE\s+)?INTO\s+gov_search',
                    re.I | re.M)

fixed, skipped = [], []
for fn in sorted(os.listdir(D)):
    if not fn.startswith("crawl_") or not fn.endswith(".py"):
        continue
    p = os.path.join(D, fn)
    src = io.open(p, encoding="utf-8", errors="ignore").read()
    if "INTO gov_search" not in src:
        continue
    lines = src.split("\n")
    out, n_add = [], 0
    for i, ln in enumerate(lines):
        m = pat_gs.match(ln)
        if m:
            ind = m.group(1)
            # 避免重复插入
            prev = "\n".join(out[-4:])
            if "2026-09-22 先提交 gov_raw" not in prev:
                out.append(ind + "# 2026-09-22: 先提交 gov_raw —— 下面手动写 FTS 会因触发器已写过同一")
                out.append(ind + "#   rowid 而 IntegrityError，若不先 commit，这条记录会被一并回滚（静默丢数据）")
                out.append(ind + "conn.commit()")
                n_add += 1
        out.append(ln)
    if n_add == 0:
        continue
    new = "\n".join(out)
    try:
        ast.parse(new)
    except SyntaxError as e:
        skipped.append((fn, str(e)[:60]))
        continue
    if not DRY:
        os.makedirs(ARCH, exist_ok=True)
        bak = os.path.join(ARCH, fn + ".bak_20260922_precommit")
        if not os.path.exists(bak):
            shutil.copy2(p, bak)
        io.open(p, "w", encoding="utf-8").write(new)
    fixed.append(fn)
    print("  ✅ %-46s 补 %d 处 commit" % (fn, n_add))

print()
print("已修 %d 个%s" % (len(fixed), "  [DRY-RUN]" if DRY else ""))
if skipped:
    print("语法失败 %d 个: %s" % (len(skipped), "; ".join("%s(%s)" % s for s in skipped[:6])))
