#!/usr/bin/env python3
import argparse
import subprocess
import sys
import time
from pathlib import Path


DEFAULT_REMOTE = "klcbot@klcweb.com"
DEFAULT_REMOTE_DIR = "/home/klcbot/bot.klcweb.com"
DEFAULT_INTERVAL = 1.0


def run(command, cwd, capture=False):
    if capture:
        return subprocess.run(
            command,
            cwd=cwd,
            check=False,
            text=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
        )

    return subprocess.run(command, cwd=cwd, check=False)


def rsync_command(remote, remote_dir, dry_run):
    command = [
        "rsync",
        "-azc",
        "--delete",
        "--itemize-changes",
        "--chmod=D777,F777",
        "--exclude=/data/***",
        "--exclude=/scripts/***",
    ]

    if dry_run:
        command.append("--dry-run")

    command.extend([
        "./",
        f"{remote}:{remote_dir.rstrip('/')}/",
    ])
    return command


def ensure_remote_dir(project_root, remote, remote_dir):
    result = run(
        ["ssh", "-o", "BatchMode=yes", remote, f"mkdir -p '{remote_dir}'"],
        cwd=project_root,
        capture=True,
    )
    if result.returncode != 0:
        raise RuntimeError(result.stdout.strip() or "failed to create remote directory")


def chmod_remote(project_root, remote, remote_dir):
    result = run(
        ["ssh", "-o", "BatchMode=yes", remote, f"chmod -R 777 '{remote_dir}'"],
        cwd=project_root,
        capture=True,
    )
    if result.returncode != 0:
        raise RuntimeError(result.stdout.strip() or "failed to chmod remote directory")


def check_changes(project_root, remote, remote_dir):
    result = run(rsync_command(remote, remote_dir, dry_run=True), cwd=project_root, capture=True)
    if result.returncode != 0:
        raise RuntimeError(result.stdout.strip() or "rsync dry-run failed")

    lines = [line for line in result.stdout.splitlines() if line.strip()]
    return lines


def sync(project_root, remote, remote_dir):
    result = run(rsync_command(remote, remote_dir, dry_run=False), cwd=project_root)
    if result.returncode != 0:
        raise RuntimeError("rsync sync failed")
    chmod_remote(project_root, remote, remote_dir)


def main():
    parser = argparse.ArgumentParser(
        description="Watch local project files and sync live server when they differ."
    )
    parser.add_argument("--remote", default=DEFAULT_REMOTE)
    parser.add_argument("--remote-dir", default=DEFAULT_REMOTE_DIR)
    parser.add_argument("--interval", type=float, default=DEFAULT_INTERVAL)
    parser.add_argument("--once", action="store_true", help="Check once, sync if needed, then exit.")
    args = parser.parse_args()

    project_root = Path(__file__).resolve().parents[1]

    try:
        ensure_remote_dir(project_root, args.remote, args.remote_dir)
    except RuntimeError as err:
        print(f"Remote setup failed: {err}", file=sys.stderr)
        return 1

    print(
        f"Watching {project_root} -> {args.remote}:{args.remote_dir} "
        f"every {args.interval:g}s; excluding data/ and scripts/"
    )

    while True:
        try:
            changes = check_changes(project_root, args.remote, args.remote_dir)
            if changes:
                print("Changes detected:")
                for line in changes:
                    print(line)
                sync(project_root, args.remote, args.remote_dir)
                print("Sync complete.")
            elif args.once:
                print("Server is already in sync.")
        except RuntimeError as err:
            print(f"Sync check failed: {err}", file=sys.stderr)

        if args.once:
            break

        time.sleep(max(args.interval, 0.1))

    return 0


if __name__ == "__main__":
    raise SystemExit(main())
