#!/bin/bash

# debug script
set -x

# These are the only lines that should require updating
frequency_mins=2

# These values are automatically determined based on the scipt path
sync_script=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$sync_script")
cronjob="*/${frequency_mins} * * * * ${sync_script}"
script_name=$(basename "$sync_script")

# Get current crontab content, suppress error if crontab is empty
current_crontab=$(crontab -l 2>/dev/null)

# Check if the exact cron job already exists using fixed string (-F) and whole line (-x) match
if echo "$current_crontab" | grep -Fxq "$cronjob"; then
  echo "${script_name} cron job is already correctly configured."
else
  echo "${script_name} cron job needs update or addition."

  # Use command grouping to construct the new crontab content:
  # 1. List current crontab (or nothing if empty), suppressing errors.
  # 2. Filter out any existing lines related to this specific script.
  # 3. Echo the desired cron job line.
  { crontab -l 2>/dev/null | grep -v "$sync_script"; echo "$cronjob"; } | crontab -
  update_result=$?

  if [[ $update_result -eq 0 ]]; then
      echo "cron job updated/added successfully."
  else
      echo "Warning: Failed to update crontab." >&2
  fi
fi

# navigate to the repo
cd "${script_dir}" || (echo 'unable to find repo' && exit 1)

# if this is macos, make sure '/usr/local/git/git-google/bin' is in $PATH
if [[ "$OSTYPE" == "darwin"* ]]; then
  if ! echo "$PATH" | grep -q "/usr/local/git/git-google/bin"; then
    export PATH="/usr/local/git/git-google/bin:$PATH"
  fi
fi

# Stage ALL changes, including new files and modifications
git add .

# Check if there are any *meaningful* staged changes (respecting diff filters)
# git diff --staged --quiet exits with 0 if NO differences, 1 if differences exist.
# The '!' negates the exit status, so the 'if' block runs if there ARE differences.
if ! git diff --staged --quiet; then
  # Only commit if there are staged changes visible after filtering
  echo "Staged changes detected, creating commit..."
  # Use -m because we already staged everything with 'git add .'
  git commit -m "${script_name} ($(hostname -s)) $(date +"%Y-%m-%dT%H:%M:%SZ")"
else
  echo "No relevant changes detected to commit (changes might be filtered)."
  # Optional but recommended: Reset the index if the only staged changes were filtered out.
  # This prevents the file from showing as "changes staged for commit" on a later 'git status'
  # if only the filtered line was changed and staged by 'git add .'.
  git reset HEAD --quiet
fi

# make sure we are authenticated with git origin
if ! git remote update origin --prune; then
  echo 'unable to authenticate to remote'
  exit 1
fi

local_commit=$(git rev-parse HEAD)
remote_commit=$(git rev-parse origin/main)

if [[ "$local_commit" != "$remote_commit" ]]; then
  # sleep for a random time between 1-45 seconds to avoid collisions
  sleepy_time=$(( ( RANDOM % 45 )  + 1 ))
  echo "sleeping for $sleepy_time seconds..."
  sleep $sleepy_time
else
  echo 'no pending changes to sync, exiting...'
  exit 0
fi

# which is newer, our code or the origin?
local_commit=$(git rev-parse HEAD)
remote_commit=$(git rev-parse origin/main)

if [[ "$local_commit" == "$remote_commit" ]]; then
  echo "local and remote are in sync"
elif git merge-base --is-ancestor "$local_commit" "$remote_commit"; then
  echo "remote is ahead of local"
  git pull --rebase origin main
elif git merge-base --is-ancestor "$remote_commit" "$local_commit"; then
  echo "local is ahead of remote"
  git push origin main
else
  echo "local and remote have diverged"
  # if remote is newer, use a 'theirs' strategy
  if [[ $(git log --pretty=format:"%at" -n 1 origin/main) -gt $(git log --pretty=format:"%at" -n 1 HEAD) ]]; then
    echo "remote is newer"
    git pull --rebase -X theirs origin main
  else
    echo "local is newer"
    git pull --rebase -X ours origin main
  fi
  git push origin main
fi

