import re, sys

path = "/home/uijktpth/signalmark/app.py"
with open(path, "r", encoding="utf-8") as f:
    src = f.read()

# --- Guard: don't run twice ---
if "_link_inject_tracks_to_messages" in src:
    print("ALREADY PATCHED - skipping")
    sys.exit(0)

func = '''
def _link_inject_tracks_to_messages() -> int:
    """Assign gmail_id to injected (sm_) tracks that lack one by matching
    them to history/sent tracks for the same recipient with the nearest
    send time.  This lets an opened injected email surface 2 ticks in the
    Gmail list.  Returns the number of tracks linked."""
    try:
        from collections import defaultdict
    except Exception:
        return 0

    db = get_db()
    orphans = db.execute(
        "SELECT track_id, recipient, subject, sent_at FROM tracks "
        "WHERE source='inject' AND (gmail_id IS NULL OR gmail_id='')"
    ).fetchall()
    if not orphans:
        return 0

    sent = db.execute(
        "SELECT gmail_id, recipient, sent_at, subject FROM tracks "
        "WHERE gmail_id IS NOT NULL AND gmail_id != '' AND source='history'"
    ).fetchall()

    def _epoch(iso):
        if not iso:
            return None
        try:
            dt = datetime.fromisoformat(iso)
            if dt.tzinfo is None:
                dt = dt.replace(tzinfo=timezone.utc)
            return dt.timestamp()
        except Exception:
            return None

    by_recipient = defaultdict(list)
    for gid, rec, st, subj in sent:
        by_recipient[(rec or "").lower()].append({
            "gmail_id": gid, "sent_at": st, "subject": subj,
        })

    linked = 0
    for track_id, recipient, subject, sent_at in orphans:
        rec_key = ((recipient or "") or "").lower()
        if not rec_key or rec_key not in by_recipient:
            continue
        target_t = _epoch(sent_at) or 0.0
        best = None
        best_key = None
        for cand in by_recipient[rec_key]:
            ct = _epoch(cand["sent_at"]) or 0.0
            delta = abs(ct - target_t)
            subj_match = (
                subject and cand["subject"] and
                str(subject).strip().lower() == str(cand["subject"]).strip().lower()
            )
            score = (0 if subj_match else 1, delta)
            if best_key is None or score < best_key:
                best_key = score
                best = cand
        if best is not None and best_key is not None and best_key[1] <= 1200.0:
            db.execute(
                "UPDATE tracks SET gmail_id=? WHERE track_id=? "
                "AND (gmail_id IS NULL OR gmail_id='')",
                (best["gmail_id"], track_id),
            )
            linked += 1
    db.commit()
    return linked

'''

# 1) Insert function before the background-sync comment block.
marker = "# \u2500\u2500 Background sync (safe for LSAPI \u2014 threads, no fork) \u2500\u2500"
if marker not in src:
    # fallback marker match
    m = re.search(r"^# \u2500\u2500 Background sync.*$", src, re.M)
    if not m:
        print("ERROR: could not find background sync marker")
        sys.exit(1)
    marker = m.group(0)

src = src.replace(marker, func + marker, 1)

# 2) Call the linker at the end of perform_sync, before the history set.
call_anchor = '    set_setting("gmail_last_history_id", str(history_id) if history_id else "")'
if call_anchor not in src:
    print("ERROR: perform_sync anchor not found")
    sys.exit(1)
src = src.replace(
    call_anchor,
    '    try:\n'
    '        _linked = _link_inject_tracks_to_messages()\n'
    '        if _linked:\n'
    '            log.info("perform_sync: linked %d inject tracks to messages", _linked)\n'
    '    except Exception as _le:\n'
    '        log.error("perform_sync: linking failed: %s", _le)\n'
    + call_anchor,
    1,
)

with open(path, "w", encoding="utf-8") as f:
    f.write(src)
print("PATCH OK")
