#!/usr/bin/env python
r"""
backup_history.py — rotating backups of Malin's conversation history.

Watches C:\malin\malin_history.json and, whenever it changes, saves a timestamped
copy into C:\malin\history_backups\, keeping the most recent N. So a stray restart,
crash, accidental clear, or corruption can never cost you a good run — you just copy
a backup back over malin_history.json and restart her.

Runs standalone (does NOT touch the live harness, so her current run stays intact).
On the 5090:  cd C:\malin   then   py backup_history.py     (leave it running)
Ctrl+C to stop.

To RESTORE a run later:
  1. Stop Malin (Ctrl+C in her window)
  2. Copy the backup you want from C:\malin\history_backups\ over C:\malin\malin_history.json
  3. Restart her (py malin.py)
"""
import datetime, hashlib, os, shutil, time

HIST       = r"C:\malin\malin_history.json"
BACKUP_DIR = r"C:\malin\history_backups"
INTERVAL   = 120     # check every 2 minutes; only copies when the file actually changed
KEEP       = 100     # how many timestamped backups to retain


def file_hash(path):
    try:
        with open(path, "rb") as f:
            return hashlib.md5(f.read()).hexdigest()
    except Exception:
        return None


def main():
    os.makedirs(BACKUP_DIR, exist_ok=True)
    print(f"[backup] watching {HIST}")
    print(f"[backup] -> {BACKUP_DIR}, every {INTERVAL}s, keeping last {KEEP}. Ctrl+C to stop.")
    last = None
    while True:
        try:
            cur = file_hash(HIST)
            if cur and cur != last and os.path.exists(HIST):
                stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                dst = os.path.join(BACKUP_DIR, f"malin_history_{stamp}.json")
                shutil.copy2(HIST, dst)
                shutil.copy2(HIST, os.path.join(BACKUP_DIR, "malin_history_latest.json"))
                last = cur
                # prune oldest beyond KEEP (timestamped files start with 'malin_history_2...')
                stamped = sorted(f for f in os.listdir(BACKUP_DIR)
                                 if f.startswith("malin_history_2") and f.endswith(".json"))
                for old in stamped[:-KEEP]:
                    try:
                        os.remove(os.path.join(BACKUP_DIR, old))
                    except Exception:
                        pass
                print(f"[backup] {datetime.datetime.now():%H:%M:%S} saved {os.path.basename(dst)} "
                      f"({len(stamped)} kept)")
        except Exception as e:
            print(f"[backup] error: {e}")
        time.sleep(INTERVAL)


if __name__ == "__main__":
    main()
