#!/bin/bash
################################################################################
# Script Name: version/3.7.5/UPDATE.sh
# Description: Apply version 3.7.5:
#              - the scheduled jobs a native install never created
#              - the CLI entry point the installer replaced too late
#              - a dispatcher that could hand a command to itself
#              - an install that adopts a checkout can reach the mirror
#              - the webmail: opening a draft no longer rewrites it, and the
#                sidebar's overlays are no longer positioned against the drawer
#              This script repairs the first two rather than reporting them:
#              on every server installed before this release they are wrong,
#              and nothing on the machine looks unusual.
# Company/Brand: HiTechCloud by Pho Tue SoftWare Solutions JSC
################################################################################

set -uo pipefail
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
ok()   { echo -e "[3.7.5] ${GREEN}✓${NC} $*"; }
warn() { echo -e "[3.7.5] ${YELLOW}!${NC} $*" >&2; }
# A release whose subject is the product asserting what it does not do should
# not end with "applied" over the top of an error. Anything bad() reports is
# counted, the last line says so, and the status is non-zero: the update path
# logs that as an error rather than a line in a file nobody opens. It does not
# abort or roll anything back.
FAILURES=0
bad()  { echo -e "[3.7.5] ${RED}✗${NC} $*" >&2; FAILURES=$((FAILURES + 1)); }
[[ $EUID -eq 0 ]] || { echo "[3.7.5] This update must run as root." >&2; exit 1; }

VERSION="3.7.5"
BIN=/usr/local/bin
CRON=/etc/cron.d/hitechcloud
WEBMAIL_SRC="${HITECHCLOUD_WEBMAIL_SRC:-/opt/hitechcloud/hitechcloudmail/webmail}"
DRY_RUN="${HITECHCLOUD_UPDATE_DRY_RUN:-0}"
run() { if [[ "$DRY_RUN" == 1 ]]; then echo "[3.7.5] would: $*"; else "$@"; fi; }

mkdir -p /usr/local/hitechcloud /etc/hitechcloud 2>/dev/null || true
echo "$VERSION" > /usr/local/hitechcloud/version 2>/dev/null || true
echo "$VERSION" > /etc/hitechcloud/version 2>/dev/null || true

# 1. The entry point, first, because step 2 depends on it.
#
#    /usr/local/bin/hitechcloudcli should be the compiled CLI. On a server
#    whose install or update left the bash dispatcher there instead, the
#    scheduled-jobs command in step 2 does not exist to be run - and
#    /usr/local/bin/hitechcloud-rustcli is a symlink to this same path, so
#    before this release the dispatcher in that position handed every command
#    to itself, one process deeper each time, without a bottom.
is_elf() { [[ -f "$1" ]] && [[ "$(od -An -t x1 -N 4 "$1" 2>/dev/null | tr -d ' \n')" == "7f454c46" ]]; }

if is_elf "${BIN}/hitechcloudcli"; then
    ok "hitechcloudcli is the compiled entry point"
    if [[ -e "${BIN}/hitechcloud-rustcli" ]] && ! is_elf "${BIN}/hitechcloud-rustcli"; then
        run ln -sf hitechcloudcli "${BIN}/hitechcloud-rustcli"
        ok "hitechcloud-rustcli pointed back at it"
    fi
elif [[ -e "${BIN}/hitechcloudcli" ]]; then
    warn "${BIN}/hitechcloudcli is the bash dispatcher, not this release's compiled binary.
  Commands still run, but the scheduled-jobs repair below cannot. Put it right with:
    hitechcloudcli update
  or fetch hitechcloudcli-linux-\$(uname -m) from the release and install it there."
fi

# 2. The scheduled jobs.
#
#    Every native install before 3.7.5 came up without them. INSTALL.sh called
#    `hitechcloudcli native-install` in step 7 and installed the compiled CLI in
#    step 9, so the install was served by native/install.sh - the shell twin,
#    which has no /etc/cron.d/hitechcloud step at all. Eighteen jobs: the health
#    monitor, send-limit enforcement, the status-page probes, audit ingest,
#    backups, statistics. A server without them looks exactly like a healthy
#    one, which is why this repairs rather than reports.
#
#    The command is idempotent - it adds what is missing and leaves the rest -
#    so it is safe on a server that already has them.
if [[ ! -f "$CRON" ]] || ! grep -q 'hitechcloudcli sentinel' "$CRON" 2>/dev/null; then
    if is_elf "${BIN}/hitechcloudcli"; then
        if run "${BIN}/hitechcloudcli" native-install --scheduled-jobs-only >/dev/null 2>&1; then
            # Counted from the file afterwards, not assumed - and a dry run says
            # what it would do rather than claiming it did it.
            if [[ "$DRY_RUN" == 1 ]]; then
                ok "this server has no scheduled jobs; they would be installed"
            else
                ok "scheduled jobs installed ($(grep -c 'hitechcloudcli' "$CRON" 2>/dev/null || echo 0) job(s)) - this server had none"
            fi
        else
            bad "the scheduled jobs could not be installed. Nothing is monitoring this server.
  Run it and read the output:  hitechcloudcli native-install --scheduled-jobs-only"
        fi
    else
        bad "this server has no scheduled jobs and no compiled CLI to install them with.
  Nothing is monitoring it. Fix the entry point above first, then run:
    hitechcloudcli native-install --scheduled-jobs-only"
    fi
else
    ok "scheduled jobs already in place ($(grep -c 'hitechcloudcli' "$CRON" 2>/dev/null || echo 0) job(s))"
fi

# 3. The webmail carries two fixes, both in the built frontend, so they arrive
#    only if it was rebuilt. Checked by looking for a file only this release
#    has rather than by trusting that the rebuild ran.
if systemctl list-unit-files 2>/dev/null | grep -q '^hitechcloud-webmail\.service'; then
    if [[ -f "${WEBMAIL_SRC}/frontend/src/utils/appPortal.js" ]]; then
        ok "webmail source is this release"
    else
        run "${BIN}/hitechcloudcli" native-webmail update >/dev/null 2>&1 \
            && ok "webmail rebuilt from this release" \
            || warn "the webmail is still the previous release; run: hitechcloudcli native-webmail update"
    fi
fi

if [[ "$FAILURES" -eq 0 ]]; then
    ok "Version ${VERSION} applied."
else
    bad "Version ${VERSION} applied, with ${FAILURES} thing(s) above left undone."
    exit 1
fi
