#!/usr/bin/env python3

import argparse
import time
import subprocess
from threading import Timer
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from pathlib import Path

# PRODUCTION CONFIGURATION
local_dir = "//home/sgbv/obsidian/"
remote_dest = "ish:/root/obsidian/"
debounce_seconds = 2.0

# ignore workspace ui states to prevent infinite sync loops
excludes = [
    "--exclude=.obsidian/workspace*",
    "--exclude=.trash/",
    "--exclude=.git/"
]

def build_rsync_cmd(src, dest):
    return ["rsync", "-avz", "--delete"] + excludes + [src, dest]

def pull_sync():
    print(f"pulling changes from ish to arch...")
    subprocess.run(build_rsync_cmd(remote_dest, local_dir))
    print("pull complete.")

def push_sync():
    print(f"pushing changes from arch to ish...")
    subprocess.run(build_rsync_cmd(local_dir, remote_dest))
    print("push complete.")

class watchdog_push_handler(FileSystemEventHandler):
    def __init__(self):
        self.sync_timer = None

    def on_any_event(self, event):
        # ignore directory changes and workspace/hidden cache updates
        if event.is_directory or any(x in event.src_path for x in [".obsidian", ".trash"]):
            return
            
        print(f"local change detected: {event.event_type}")
        if self.sync_timer:
            self.sync_timer.cancel()
            
        self.sync_timer = Timer(debounce_seconds, push_sync)
        self.sync_timer.start()

def watch_mode():
    print(f"arch watchdog listening on {local_dir}")
    handler = watchdog_push_handler()
    observer = Observer()
    observer.schedule(handler, local_dir, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("\nstopping watchdog...")
        observer.stop()
    observer.join()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="arch sync node")
    parser.add_argument("mode", nargs="?", default="watch", choices=["watch", "push", "pull"])
    args = parser.parse_args()

    if args.mode == "pull":
        pull_sync()
    elif args.mode == "push":
        push_sync()
    else:
        watch_mode()
