#!/usr/bin/env bash

if [[ $UID != 0 ]]; then
    echo "Update script must be run as root"
    exit 1
fi

check_dependencies () {
  for cmd in "$@"; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      echo "This script requires \"${cmd}\" to be installed"
      exit 1
    fi
  done
}

check_semver_range () {
  local range="${1}"
  local version="${2}"
  "${UMBREL_ROOT}/scripts/umbrel-os/semver" -r "${range}" "${version}" | grep --quiet "^${version}$"
}

check_dependencies jq curl rsync

UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"

update_type=""
if [[ "${1}" == "--ota" ]]; then
  update_type="ota"
elif [[ "${1}" == "--path" ]]; then
  update_type="path"
  update_path="${2}"
elif [[ "${1}" == "--repo" ]]; then
  update_type="repo"
  descriptor="${2}"
  if [[ "${descriptor}" != *"#"* ]]; then
    descriptor="${descriptor}#master"
  fi
  repo="${descriptor%%#*}"
  branch="${descriptor#*#}"
else
  echo "Update requires \"--ota\", \"--path <path>\", or \"--repo user/repo[#branch]\" option."
  exit 1
fi

if [[ "${update_type}" == "repo" ]]; then
  repo_path="/tmp/umbrel-update/"
  rm -rf "${repo_path}" 2> /dev/null || true
  mkdir -p "${repo_path}"
  git clone --single-branch --branch "${branch}" "https://github.com/${repo}.git" "${repo_path}"

  # Patch version to show development build
  commit=$(git --git-dir "${repo_path}/.git" rev-parse --short HEAD)
  mv "${repo_path}/info.json" "${repo_path}/info.json.orig"
  jq \
    --arg commit "${commit}" \
    '.build = $commit' \
    "${repo_path}/info.json.orig" \
    > "${repo_path}/info.json"

  # Now hand over to the path updater
  update_type="path"
  update_path="${repo_path}"
fi

if [[ "${update_type}" == "path" ]] && [[ ! -f "${update_path}/.umbrel" ]]; then
  echo "Update path doesn't seem to be an Umbrel install."
  exit 1
fi
  
# This will cover only --repo and --path usage
if [[ "${update_type}" == "path" ]] && [[ "$*" != *"--skip-version-check"* ]]; then
  current_version=$(cat "${UMBREL_ROOT}/info.json" | jq --raw-output '.version')
  update_requires=$(cat "${update_path}/info.json" | jq --raw-output '.requires')

  if ! check_semver_range "${update_requires}" "${current_version}"; then
    echo "Error: Your Umbrel must first satisify this version: ${update_requires}"
    echo "       Your Umbrel version is: ${current_version}"
    exit 1
  fi
fi

if [[ "${update_type}" == "ota" ]]; then
  RELEASE=$(cat "$UMBREL_ROOT"/statuses/update-status.json | jq .updateTo -r)
elif [[ "${update_type}" == "path" ]]; then
  RELEASE=$(cat "$update_path"/info.json | jq .version -r)
fi

echo
echo "======================================="
echo "=============== UPDATE ================"
echo "======================================="
echo "========== Stage: Download ============"
echo "======================================="
echo

# Make sure an update is not in progres
if [[ -f "$UMBREL_ROOT/statuses/update-in-progress" ]]; then
    echo "An update is already in progress. Exiting now."
    exit 2
fi

echo "Creating lock"
touch "$UMBREL_ROOT"/statuses/update-in-progress

# Cleanup just in case there's temp stuff lying around from previous update
echo "Cleaning up any previous mess"
[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE"

# Update status file
cat <<EOF > "$UMBREL_ROOT"/statuses/update-status.json
{"state": "installing", "progress": 10, "description": "Downloading Umbrel $RELEASE", "updateTo": "$RELEASE"}
EOF

# Download new release
if [[ "${update_type}" == "ota" ]]; then
  echo "Downloading Umbrel ${RELEASE}"
  mkdir -p "${UMBREL_ROOT}/.umbrel-${RELEASE}"
  cd "${UMBREL_ROOT}/.umbrel-${RELEASE}"
  curl -L "https://github.com/getumbrel/umbrel/archive/$RELEASE.tar.gz" | tar -xz --strip-components=1
fi

# Copy over new release from path
if [[ "${update_type}" == "path" ]]; then
  echo "Copying Umbrel ${RELEASE} from ${update_path}"
  mkdir -p "${UMBREL_ROOT}/.umbrel-${RELEASE}"
  cp --recursive \
    --archive \
    --no-target-directory \
    "${update_path}" "${UMBREL_ROOT}/.umbrel-${RELEASE}"
  cd "${UMBREL_ROOT}/.umbrel-${RELEASE}"
fi

# Run update scripts
echo "Running update install scripts of the new release"
cd scripts/update
UPDATE_INSTALL_SCRIPTS=$(ls *-run.sh)
for script in $UPDATE_INSTALL_SCRIPTS; do
    if [[ -x $script ]]; then
        echo
        echo "== Begin Update Script $script =="
        ./"$script" "$RELEASE" "$UMBREL_ROOT"
        echo "== End Update Script $script =="
        echo
    fi
done

# Delete cloned repo
echo "Deleting cloned repository"
[[ -d "$UMBREL_ROOT"/.umbrel-"$RELEASE" ]] && rm -rf "$UMBREL_ROOT"/.umbrel-"$RELEASE"

echo "Removing lock"
rm -f "$UMBREL_ROOT"/statuses/update-in-progress

# Make sure the update-status file isn't stuck in an 
# unresolved state (i.e anything except "success" or "failed")

update_state=$(cat "${UMBREL_ROOT}/statuses/update-status.json" | jq .state -r)

# Show error
update_failure_status_file="${UMBREL_ROOT}/statuses/update-failure"
if [[ -f "${update_failure_status_file}" ]]; then
  reason=$(cat "${update_failure_status_file}")
  rm "${update_failure_status_file}"
  cat <<EOF > "${UMBREL_ROOT}/statuses/update-status.json"
{"state": "failed", "progress": 100, "description": "${reason}", "updateTo": ""}
EOF
fi

if [[ "${update_state}" != "success" ]] && [[ "${update_state}" != "failed" ]]; then
    # Sleep for a few seconds to make sure the user is on the update view
    sleep 8
    cat <<EOF > "${UMBREL_ROOT}/statuses/update-status.json"
{"state": "failed", "progress": 100, "description": "An unexpected error occured", "updateTo": ""}
EOF
fi

exit 0
