#!/usr/bin/env bash
# Controller revisions activate and roll back independently from the grouped web release.
set -uo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT="$ROOT/packaging/deploy-local.sh"
fails=0
check() { if [[ "$1" == 0 ]]; then printf 'ok - %s\n' "$2"; else printf 'FAIL - %s\n' "$2"; fails=$((fails + 1)); fi; }

bash -n "$SCRIPT"
check "$?" 'deploy-local.sh parses'

base_line=$(grep -n 'controller_base=$(component_convergence_base controller' "$SCRIPT" | head -1 | cut -d: -f1)
gate_line=$(grep -n 'controller_unchanged_since_stamp "$controller_base" "$deployment_sha"' "$SCRIPT" | head -1 | cut -d: -f1)
activate_line=$(grep -n 'backend-release.sh" activate controller' "$SCRIPT" | head -1 | cut -d: -f1)
receipt_line=$(grep -n 'publish_component_receipt controller "$deployment_sha"' "$SCRIPT" | head -1 | cut -d: -f1)
if [[ -n "$base_line" && -n "$gate_line" && -n "$activate_line" && -n "$receipt_line" ]] \
  && (( base_line < gate_line && gate_line < activate_line && activate_line < receipt_line )); then
  rc=0
else
  rc=1
fi
check "$rc" 'controller gate precedes independent activation and receipt publication'

stage_calls=$(grep -c 'LOCAL_GATE_ACTIVE=1 bash .*stage-backend-release.sh" controller' "$SCRIPT")
if [[ "$stage_calls" == 2 ]]; then rc=0; else rc=1; fi
check "$rc" 'controller artifacts materialize on the activation host'

if ! grep -q 'release_restart_services+=(overdeck-controller.service)' "$SCRIPT" \
  && grep -q 'for component in web web-watchdog' "$SCRIPT"; then
  rc=0
else
  rc=1
fi
check "$rc" 'web rollback neither restarts nor republishes controller convergence'

if ! grep -q 'identity_tmp=\|identity_dir=' "$SCRIPT" \
  && grep -q 'export OVERDECK_DEPLOYMENT_IDENTITY="$root/deployment-identity.json"' \
    "$ROOT/packaging/stage-backend-release.sh"; then
  rc=0
else
  rc=1
fi
check "$rc" 'controller rollback restores release-local delivery identity with the code'

TESTROOT="${XDG_CACHE_HOME:-$HOME/.cache}/overdeck/tests/controller-restart-gate/run-$$-$RANDOM"
FIXTURE="$TESTROOT/repo"
GATE_SRC="$TESTROOT/gate.sh"
mkdir -p "$FIXTURE/controller/src" "$FIXTURE/docs" "$FIXTURE/packaging"
trap 'rm -rf "$TESTROOT"' EXIT
{
  sed -n '/^CONTROLLER_RESTART_PATHS=(/,/^)/p' "$SCRIPT"
  sed -n '/^controller_unchanged_since_stamp() (/,/^)/p' "$SCRIPT"
} >"$GATE_SRC"
git init -q "$FIXTURE"
printf 'v1\n' >"$FIXTURE/controller/src/index.ts"
printf 'v1\n' >"$FIXTURE/packaging/stage-backend-release.sh"
git -C "$FIXTURE" add -A
git -C "$FIXTURE" -c user.email=t@t -c user.name=t commit -q -m base
BASE=$(git -C "$FIXTURE" rev-parse HEAD)
printf 'docs\n' >"$FIXTURE/docs/note.md"
git -C "$FIXTURE" add -A
git -C "$FIXTURE" -c user.email=t@t -c user.name=t commit -q -m docs
DOCS_ONLY=$(git -C "$FIXTURE" rev-parse HEAD)
printf 'v2\n' >"$FIXTURE/controller/src/index.ts"
git -C "$FIXTURE" add -A
git -C "$FIXTURE" -c user.email=t@t -c user.name=t commit -q -m controller
CONTROLLER_TOUCHED=$(git -C "$FIXTURE" rev-parse HEAD)

run_gate() {
  local stamp=$1 target=$2 active_rc=$3
  (
    export DEPLOY="$FIXTURE" FAKE_ACTIVE_RC="$active_rc"
    systemctl() { return "$FAKE_ACTIVE_RC"; }
    # shellcheck disable=SC1090
    source "$GATE_SRC"
    controller_unchanged_since_stamp "$stamp" "$target"
  )
}
run_gate "$BASE" "$DOCS_ONLY" 0
check "$?" 'unrelated changes keep an active controller'
! run_gate "$BASE" "$CONTROLLER_TOUCHED" 0
check "$?" 'controller source changes require immutable activation'
! run_gate "$BASE" "$DOCS_ONLY" 3
check "$?" 'an inactive controller requires immutable activation'

(( fails == 0 )) || { printf '%s check(s) failed\n' "$fails" >&2; exit 1; }
printf 'controller-restart-gate: all checks passed\n'
