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

DEPLOY="${OVERDECK_DEPLOY_DIR:-$HOME/.local/share/overdeck/deploy}"
SOURCE="$DEPLOY/packaging/kanboard/overdeck-kanboard.container"
PLUGIN="$DEPLOY/packaging/kanboard/plugins/OverdeckIncidents"
TARGET="$HOME/.config/containers/systemd/overdeck-kanboard.container"
TOKEN_FILE="$HOME/.config/overdeck/kanboard-app.env"
RELEASES="$HOME/.local/share/overdeck/kanboard-plugin-releases"
ACTIVE="$HOME/.local/share/overdeck/kanboard-plugin-active"

[[ -f "$SOURCE" && -d "$PLUGIN" && -f "$PLUGIN/Plugin.php" && -f "$PLUGIN/BoundedTaskPage.php" ]] || { printf 'Kanboard deployment assets are incomplete\n' >&2; exit 1; }
find "$PLUGIN" -type f -name '*.php' -print0 | xargs -0 -r -n1 php -l >/dev/null
[[ -f "$TOKEN_FILE" ]] || { printf 'Kanboard authentication authority is missing\n' >&2; exit 1; }
TOKEN="$(grep -E '^KANBOARD_API_TOKEN=' "$TOKEN_FILE" | cut -d= -f2-)"
[[ -n "$TOKEN" ]] || { printf 'Kanboard API token is missing\n' >&2; exit 1; }

canary() {
    local response
    local request='{"jsonrpc":"2.0","method":"overdeck.listTasksBounded","id":"deploy-canary","params":{"projectId":1,"statusId":null,"limit":1,"cursor":null,"highWater":null,"query":"","priority":null}}'
    response="$(curl --fail --silent --show-error --max-time 5 -u "jsonrpc:$TOKEN" -H 'content-type: application/json' --data "$request" http://127.0.0.1:31339/jsonrpc.php)"
    php -r '$d=json_decode(stream_get_contents(STDIN), true); $r=$d["result"]??null; if (($d["id"]??null)!=="deploy-canary" || !is_array($r) || !isset($r["tasks"],$r["high_water"],$r["exhausted"],$r["complete"],$r["order"]) || !is_array($r["tasks"]) || $r["order"]!=="id_desc" || $r["complete"]!==true) exit(1);' <<<"$response"
}

canary_absent() {
    local response
    local request='{"jsonrpc":"2.0","method":"overdeck.listTasksBounded","id":"deploy-canary","params":{"projectId":1,"statusId":null,"limit":1,"cursor":null,"highWater":null,"query":"","priority":null}}'
    response="$(curl --silent --show-error --max-time 5 -u "jsonrpc:$TOKEN" -H 'content-type: application/json' --data "$request" http://127.0.0.1:31339/jsonrpc.php)"
    php -r '$d=json_decode(stream_get_contents(STDIN), true); if (($d["id"]??null)!=="deploy-canary" || ($d["error"]["code"]??null)!==-32601) exit(1);' <<<"$response"
}

restart_and_wait() {
    systemctl --user daemon-reload
    systemctl --user restart overdeck-kanboard.service
    for _ in $(seq 1 30); do
        curl --fail --silent --show-error --max-time 2 http://127.0.0.1:31339/ >/dev/null && return
        sleep 1
    done
    return 1
}

release_hash="$(find "$PLUGIN" -type f -print0 | sort -z | xargs -0 sha256sum | sha256sum | cut -d' ' -f1)"
release="$RELEASES/$release_hash"
# Capture every restart decision before installing either candidate. Ambiguous or absent
# state deliberately compares as changed.
unit_changed=1
cmp -s "$SOURCE" "$TARGET" && unit_changed=0
previous=""
previous_canonical=""
if [[ -L "$ACTIVE" ]]; then
    previous="$(readlink "$ACTIVE")"
    previous_canonical="$(readlink -f "$ACTIVE" 2>/dev/null || true)"
fi
release_canonical="$(readlink -f "$release" 2>/dev/null || true)"
release_changed=1
[[ -n "$previous_canonical" && -n "$release_canonical" && "$previous_canonical" == "$release_canonical" ]] && release_changed=0
service_inactive=1
systemctl --user is-active --quiet overdeck-kanboard.service && service_inactive=0

mkdir -p "$RELEASES" "$(dirname "$ACTIVE")"
if [[ ! -d "$release" ]]; then
    temp="$RELEASES/.${release_hash}.$$"
    mkdir "$temp"
    cp -a "$PLUGIN"/. "$temp"/
    chmod -R a-w "$temp"
    mv "$temp" "$release"
fi
ln -sfn "$release" "$ACTIVE.new"
mv -Tf "$ACTIVE.new" "$ACTIVE"
install -Dm644 "$SOURCE" "$TARGET"

status=kept
candidate_ok=1
if (( unit_changed || release_changed || service_inactive )); then
    status=restarted
    restart_and_wait && canary || candidate_ok=0
elif ! canary; then
    status=fallback-restarted
    restart_and_wait && canary || candidate_ok=0
fi

if (( ! candidate_ok )); then
    if [[ -n "$previous" ]]; then
        ln -sfn "$previous" "$ACTIVE.new"
        mv -Tf "$ACTIVE.new" "$ACTIVE"
        if ! restart_and_wait || ! canary; then
            printf 'kanboard: rolled-back\n'
            printf 'Kanboard rollback canary failed\n' >&2
            exit 1
        fi
    else
        empty="$RELEASES/empty"
        mkdir -p "$empty"
        chmod a-w "$empty"
        ln -sfn "$empty" "$ACTIVE.new"
        mv -Tf "$ACTIVE.new" "$ACTIVE"
        if ! restart_and_wait || ! canary_absent; then
            printf 'kanboard: rolled-back\n'
            printf 'Kanboard plugin-absence canary failed\n' >&2
            exit 1
        fi
        printf 'kanboard: rolled-back\n'
        printf 'Kanboard candidate canary failed; empty plugin directory activated and absence verified\n' >&2
        exit 1
    fi
    printf 'kanboard: rolled-back\n'
    printf 'Kanboard candidate canary failed; previous release restored\n' >&2
    exit 1
fi
printf 'kanboard: %s\n' "$status"
