#!/usr/bin/env bash

set -euo pipefail
shopt -s extglob

main() {
  repo_path="$(realpath "$(dirname "$(git rev-parse --git-common-dir)")")"
  reponame="$(basename "$repo_path")"
  current_branch="$(git rev-parse --abbrev-ref HEAD)"
  main_branch="$(get_main_branch)"

  cd "$repo_path"

  fetch_origin

  update_branch "$main_branch" "origin/$main_branch"

  config="$(get_config "$reponame")"

  if [[ -n "$config" ]]; then
    update_worktrees
  fi
  # Rebase current branch on most recent originating branch
  git checkout --quiet "$current_branch"
  if [[ "$current_branch" != "$main_branch" ]]; then
    o="$(originating_branch)"
    [[ -n "$o" ]] && update_branch "$current_branch" "$o"
  fi
}

originating_branch() {
  local i res
  i=0
  res=""

  while [[ -z "$res" ]] && ((i < 100 )); do 
    res=$(git branch -r --list 'origin/*' --contains "HEAD~$i" | awk '{print $1; exit}')
    i=$((i+1))
  done

  echo "$res"
}

get_main_branch() {
  if git rev-parse --verify origin/main >/dev/null 2>&1; then
    echo main
  elif git rev-parse --verify origin/master >/dev/null 2>&1; then
    echo master
  else
    echo "No main/master branch detected">/dev/stderr
    exit 1
  fi
}

fetch_origin() {
  git diff --quiet || {
    echo branch not clean. exiting >/dev/stderr
    exit 1
  }
  
  echo "Fetching origin" >/dev/stderr
  git fetch --quiet origin
}

update_branch() {
  local local_branch remote_branch local_head remote_head
  local_branch="$1"
  remote_branch="$2"
  git checkout --quiet "$local_branch"
  local_head="$(git rev-parse --short HEAD)"
  remote_head="$(git log --pretty=format:%h -n 1 "$remote_branch")"
  if [[ "$local_head" == "$remote_head" ]]; then
    echo "No updates for $local_branch" >/dev/stderr
  else
    echo "rebasing branch $remote_branch onto $local_branch: $local_head..$remote_head" >/dev/stderr
    git rebase --quiet "$remote_branch"
  fi
}


get_config() {
  local reponame="$1"
  # shellcheck disable=SC2016
  yq --arg name "$reponame" '
    .[]
    | select((.repo | split("/").[-1] ) == $name )
  ' ~/.config/git-update.yaml || true
}

update_worktrees() {
  worktree_dir="$(jq -r .worktree_dir <<<"$config")"
  eval worktree_dir="$worktree_dir"  # expand ~
  mkdir -p "$worktree_dir"
  shopt -s nullglob
  chmod --recursive +w "$worktree_dir"/* 2>/dev/null || true
  trap 'chmod --recursive -w "$worktree_dir"/*' EXIT
  while read -r branch dir; do
    update_branch "$branch" "origin/$branch"
    ( 
      echo "Updating worktree $worktree_dir/$dir" >/dev/stderr
      if [[ -d "$worktree_dir/$dir" ]]; then
        cd "$worktree_dir/$dir"
        git checkout --quiet "origin/$branch"
      else
        git worktree add "$worktree_dir/$dir" "origin/$branch"
      fi
    )
  done < <(
    jq -r '.checkouts[] | .branch + " " + .dir' <<<"$config"
  )
}

main
