#!/usr/bin/env bash
set -Eeuo pipefail

# Do not inherit Windows executables into this D-only runtime. In particular,
# Docker Desktop's docker.exe belongs to a different image store.
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

readonly CVAT_TAG="${CVAT_TAG:-v2.70.0}"
readonly FREE_GIB_FLOOR="${FREE_GIB_FLOOR:-360}"
readonly WINDOWS_ROOT="/mnt/d/NDC_MISSIONCORE"
readonly COMPUTE_ROOT="${WINDOWS_ROOT}/workspace/mission-core-compute"
readonly RUNTIME_ROOT="${WINDOWS_ROOT}/runtime/annotation/cvat"
readonly CVAT_ROOT="${RUNTIME_ROOT}/source/cvat-${CVAT_TAG}"
readonly STATE_ROOT="/srv/mission-core-cvat"
readonly OVERRIDE_FILE="${COMPUTE_ROOT}/cvat/docker-compose.override.yml"

if [[ "${EUID}" -ne 0 ]]; then
  echo "provision_cvat_wsl.sh must run as root" >&2
  exit 2
fi

free_gib() {
  df -BG --output=avail "${WINDOWS_ROOT}" | tail -n 1 | tr -dc '0-9'
}

guard_disk() {
  local stage="$1"
  local free
  free="$(free_gib)"
  printf 'disk_guard stage=%s free_gib=%s floor_gib=%s\n' \
    "${stage}" "${free}" "${FREE_GIB_FLOOR}"
  if (( free < FREE_GIB_FLOOR )); then
    echo "D: free-space floor crossed; refusing further writes" >&2
    exit 3
  fi
}

guard_disk preflight

export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y ca-certificates curl git

if ! dpkg-query -W -f='${Status}' docker-ce 2>/dev/null \
  | grep -qx 'install ok installed'; then
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
    -o /etc/apt/keyrings/docker.asc
  chmod a+r /etc/apt/keyrings/docker.asc
  # shellcheck disable=SC1091
  . /etc/os-release
  arch="$(dpkg --print-architecture)"
  printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu %s stable\n' \
    "${arch}" "${VERSION_CODENAME}" >/etc/apt/sources.list.d/docker.list
  apt-get update
  apt-get install -y \
    docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
fi

systemctl enable --now docker
docker version
docker compose version
guard_disk docker-engine

install -d -m 0750 \
  "${STATE_ROOT}/volumes/cvat_db" \
  "${STATE_ROOT}/volumes/cvat_data" \
  "${STATE_ROOT}/volumes/cvat_keys" \
  "${STATE_ROOT}/volumes/cvat_logs" \
  "${STATE_ROOT}/volumes/cvat_inmem_db" \
  "${STATE_ROOT}/volumes/cvat_events_db" \
  "${STATE_ROOT}/volumes/cvat_cache_db" \
  "${RUNTIME_ROOT}/source" \
  "${RUNTIME_ROOT}/reports"

if [[ ! -d "${CVAT_ROOT}/.git" ]]; then
  git clone --depth 1 --branch "${CVAT_TAG}" \
    https://github.com/cvat-ai/cvat.git "${CVAT_ROOT}"
fi

test "$(git -C "${CVAT_ROOT}" describe --tags --exact-match)" = "${CVAT_TAG}"
test -f "${OVERRIDE_FILE}"
guard_disk cvat-source

export CVAT_VERSION="${CVAT_TAG}"
export CVAT_HOST="localhost"
export CVAT_HTTP_PORT="8080"
export COMPOSE_PROJECT_NAME="missioncore-cvat"

compose=(
  docker compose
  --project-directory "${CVAT_ROOT}"
  -f "${CVAT_ROOT}/docker-compose.yml"
  -f "${OVERRIDE_FILE}"
)

"${compose[@]}" config --quiet
mapfile -t images < <("${compose[@]}" config --images | sort -u)
for image in "${images[@]}"; do
  guard_disk "before-pull:${image}"
  docker pull "${image}"
  guard_disk "after-pull:${image}"
done

"${compose[@]}" up -d --no-build
guard_disk cvat-started

deadline=$((SECONDS + 600))
until curl --fail --silent --show-error http://localhost:8080/api/server/about \
  >/dev/null; do
  if (( SECONDS >= deadline )); then
    "${compose[@]}" ps
    echo "CVAT did not become ready within 600 seconds" >&2
    exit 4
  fi
  sleep 5
done

report="${RUNTIME_ROOT}/reports/deployment-$(date -u +%Y%m%dT%H%M%SZ).txt"
{
  printf 'cvat_tag=%s\n' "${CVAT_TAG}"
  printf 'cvat_commit=%s\n' "$(git -C "${CVAT_ROOT}" rev-parse HEAD)"
  printf 'docker_version=%s\n' "$(docker version --format '{{.Server.Version}}')"
  printf 'compose_version=%s\n' "$(docker compose version --short)"
  printf 'free_gib=%s\n' "$(free_gib)"
  printf 'generated_at_utc=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  docker image inspect "${images[@]}" \
    --format 'image={{index .RepoTags 0}} id={{.Id}} size={{.Size}}'
  "${compose[@]}" ps
} | tee "${report}"

printf 'CVAT ready at http://localhost:8080\nreport=%s\n' "${report}"
