#!/bin/bash
set -euo pipefail

# Function to wait for a service to become available
wait_for_service() {
  local url="$1"
  local timeout=30 # seconds
  local start_time=$(date +%s)
  echo "Waiting for service at $url to become available (timeout: ${timeout}s)..."
  while :; do
    if curl --silent --fail "$url" >/dev/null; then
      echo "Service at $url is up!"
      return 0
    fi
    current_time=$(date +%s)
    if ((current_time - start_time >= timeout)); then
      echo "Error: Service at $url did not become available within ${timeout}s."
      return 1
    fi
    sleep 1
  done
}

deploy_expressjs_blog() {
  local ref="$1"
  local custom_path="${2:-}"
  local custom_env="${3:-}"
  local branch="${ref#refs/heads/}"
  local path="${custom_path:-/srv/jasonpoage.com/expressjs-blog-$branch}"
  local envfile="${custom_env:-/srv/jasonpoage.com/$branch.env}"

  set -x

  GIT_DIR="/srv/jasonpoage.com/expressjs-blog.git"

  if [[ "$branch" == "production" || "$branch" == "main" || "$branch" == "testing" ]]; then

    GIT_WORK_TREE="$path" git checkout -f "$branch"

    cd "$path" || return 1
    [[ -z "$custom_path" ]] && ln -f "$envfile" "$path/.env" || {
      cp -f "$envfile" "$path/.env"
    }
    yarn
    yarn combine:css
    [[ -z "$custom_path" ]] && systemctl --user restart express-blog@"$branch".service

    if [[ -d "$path/content" ]]; then
      cd "$path/content" || return 1
      current_commit=$(git rev-parse HEAD)
      git fetch origin
      latest_commit=$(git rev-parse origin/main)

      if [[ "$current_commit" != "$latest_commit" ]]; then
        git reset --hard origin/main
        echo "Content updated to latest commit"
      else
        echo "Content already up to date"
      fi
      return 0
    fi
    local force_refresh="${4:-false}"
    if [[ "$force_refresh" == "true" ]] || [[ ! -d "$path/content" ]]; then
      git clone --branch main /srv/jasonpoage.com/expressjs-blog-posts.git "$path/content"
    fi
  fi
  set +x
}

run_postreceive_tests() {
  local branch="$1"
  local tmpdir pidfile logfile
  tmpdir=$(mktemp -d)
  pidfile="$tmpdir/test.pid"
  logfile="$tmpdir/test.log"
  trap "kill $(cat "$pidfile" 2>/dev/null) 2>/dev/null; rm -rf \"$tmpdir\"" EXIT

  git clone . "$tmpdir" --quiet --branch "$branch"

  deploy_expressjs_blog "refs/heads/$branch" "$tmpdir" "/srv/jasonpoage.com/${branch}.env"

  cd "$tmpdir" || return 1
  export TEST_PORT=4123

  export NODE_ENV=testing
  nohup yarn start >>"$logfile" 2>&1 &
  echo $! >"$pidfile"

  # Wait for the application to become responsive
  if ! wait_for_service "http://127.0.0.1:$TEST_PORT"; then
    echo "Application did not start or respond. Check logs:"
    cat "$logfile" # Display logs on failure
    return 1
  fi

  if ! npm run test:postreceive; then
    kill "$(cat "$pidfile")" 2>/dev/null
    cat "$logfile"
    return 1
  fi

  kill "$(cat "$pidfile")" 2>/dev/null
}

while read -r oldrev newrev ref; do
  branch="${ref#refs/heads/}"
  if run_postreceive_tests "$branch"; then
    deploy_expressjs_blog "$ref"
  else
    echo "Post-receive tests failed. Deployment aborted."
    exit 1
  fi
done
