#!/usr/bin/env bash
#!@bash@/bin/bash
# shellcheck shell=bash

set -o errexit
set -o nounset
set -o pipefail
shopt -s lastpipe

usage="$(basename "$0") [-h] [--diff] [NODE]
Check if deployed config is actually the one on master
By default check all nodes

where:
    -h        Show this help text
    --diff    Show diff with nvd

Exemple:
    check-deployment web01"

while [[ $# -gt 0 ]]; do
  case "$1" in
  --help|-h)
    echo "$usage"
    exit 0
    ;;

  --diff)
    diff=y
    ;;

  *)
    if [[ -z ${node-} ]]; then
      node="$1"
    else
      echo "Too many arguments. Help:"
      echo "$usage"
      exit 1
    fi
    ;;
  esac
  shift
done

#############
# go to tmp #
#############

TMP=$(mktemp -d)
GIT_TOP_LEVEL=$(git rev-parse --show-toplevel)

echo "Cloning local main..."
git clone -q --branch main --single-branch "$GIT_TOP_LEVEL" "$TMP"
pushd "$TMP" > /dev/null || exit 2

####################
# Evaluate configs #
####################

colmena_failed () {
  >&2 echo "Colmena failed. Check your config. Logs:"
  >&2 cat "$COLMENA_LOGS"
  exit 3
}

COLMENA_LOGS=$(mktemp)

echo "Evaluating configs..."
# Disable warning because of '${}'
# shellcheck disable=SC2016
RESULTS=$(colmena eval -E '{ nodes, lib, ...}: lib.mapAttrsToList (k: v: { machine = k; path = v.config.system.build.toplevel; drv = v.config.system.build.toplevel.drvPath; domain = "${v.config.networking.hostName}.${v.config.networking.domain}"; }) nodes' 2> "$COLMENA_LOGS" || colmena_failed)

rm "$COLMENA_LOGS"
echo "Evaluation finished"

#####################################
# retrieve and check current-system #
#####################################

retrieve_current_system () {
  # TODO implement a less invasive method
  ssh -n "root@$1" "readlink -f /run/current-system"
}


return_status=0
echo "$RESULTS" | @jq@/bin/jq -c '.[]' |
while IFS=$'\n' read -r c; do

  machine=$(echo "$c" | @jq@/bin/jq -r '.machine')
  if [[ -n ${node-} ]] && [[ "$machine" != "$node" ]]; then
    echo "Skipping ${machine}"
    continue
  fi
  expected_path=$(echo "$c" | @jq@/bin/jq -r '.path')
  domain=$(echo "$c" | @jq@/bin/jq -r '.domain')
  drv_path=$(echo "$c" | @jq@/bin/jq -r '.drv')

  err=0
  current_path=$(retrieve_current_system "$domain") || err=1
  if [[ "1" == "${err}" ]] ; then
    echo "❌ failed to contact $domain !"
    continue
  fi

  if [ "$expected_path" == "$current_path" ] ; then
    echo "✅ $machine -> OK"
  elif [[ -n ${diff-} ]] ; then
    nix-copy-closure --from "root@$domain" "$current_path"
    nix-store -r "$drv_path"
    echo "$machine -> error. nvd output:"
    @nvd@/bin/nvd  diff "$expected_path" "$current_path"
    return_status=1
  else
    echo "☠️ $machine -> error:"
    echo "   - Expected system: $expected_path"
    echo "   - Current system:  $current_path"
    return_status=1
  fi
done

popd > /dev/null || exit 2
rm -r "$TMP"

exit $return_status