#!/usr/bin/env bash
#
# open-dmo employee installer (Linux x86_64, no sudo).
#
#   curl -fsSL https://cdn.jsdelivr.net/npm/opendmo/install.sh | bash
#
# Installs the opendmo binary payload into ~/.local/share/opendmo and puts an
# `opendmo` wrapper on PATH at ~/.local/bin/opendmo. Office state (~/.open-dmo)
# is never touched, by install or by --uninstall.
#
# Download source — two modes:
#   default        the public npm registry: the opendmo-linux-x64 package
#                  tarball, verified against the registry's sha512 integrity.
#   payload dir    --url <base> or OPENDMO_INSTALL_URL: an office-internal
#                  http/file base serving opendmo-linux-x64.tar.gz +
#                  SHA256SUMS (air-gapped offices, the test harness).
#
# Options (pipe form: `| bash -s -- --version 0.2.0`):
#   --url <base>       Payload-dir base URL (or OPENDMO_INSTALL_URL env var)
#   --registry <base>  npm registry base (default https://registry.npmjs.org,
#                      or the OPENDMO_NPM_REGISTRY environment variable)
#   --version <X.Y.Z>  Pin a package version (registry mode only)
#   --uninstall        Remove the installed payload and the PATH wrapper
#   --join <file>      Join the office right after installing (runs
#                      `opendmo init --join <file>`), making install + join
#                      one command. In pipe form there is no terminal to
#                      prompt on, so pass --employee and --name with it.
#   --employee <id>    Your employee id (employees.yaml), for --join
#   --name "<name>"    Your display name, for --join

set -euo pipefail

PLATFORM_PKG="opendmo-linux-x64"
PAYLOAD_TARBALL="opendmo-linux-x64.tar.gz"
INSTALL_DIR="$HOME/.local/share/opendmo"
BIN_DIR="$HOME/.local/bin"
WRAPPER="$BIN_DIR/opendmo"

say() { printf '%s\n' "$*"; }
die() {
    printf 'install.sh: %s\n' "$*" >&2
    exit 1
}

BASE_URL="${OPENDMO_INSTALL_URL:-}"
REGISTRY="${OPENDMO_NPM_REGISTRY:-https://registry.npmjs.org}"
VERSION=""
UNINSTALL=false
JOIN_FILE=""
EMPLOYEE=""
NAME=""

while [[ $# -gt 0 ]]; do
    case $1 in
        --url)
            BASE_URL="${2:?--url requires a value}"
            shift 2
            ;;
        --registry)
            REGISTRY="${2:?--registry requires a value}"
            shift 2
            ;;
        --version)
            VERSION="${2:?--version requires a value}"
            shift 2
            ;;
        --uninstall)
            UNINSTALL=true
            shift
            ;;
        --join)
            JOIN_FILE="${2:?--join requires a value}"
            shift 2
            ;;
        --employee)
            EMPLOYEE="${2:?--employee requires a value}"
            shift 2
            ;;
        --name)
            NAME="${2:?--name requires a value}"
            shift 2
            ;;
        *)
            die "unknown option: $1"
            ;;
    esac
done

if [[ -n "$JOIN_FILE" && ! -f "$JOIN_FILE" ]]; then
    die "join file not found: $JOIN_FILE"
fi

if [[ "$UNINSTALL" == "true" ]]; then
    rm -rf "$INSTALL_DIR"
    rm -f "$WRAPPER"
    say "opendmo removed ($INSTALL_DIR and $WRAPPER)."
    say "Your office data in ~/.open-dmo was left alone."
    exit 0
fi

# This phase ships one platform.
if [[ "$(uname -s)" != "Linux" || "$(uname -m)" != "x86_64" ]]; then
    die "this installer covers Linux x86_64 only for now (found: $(uname -s) $(uname -m))"
fi

if ! command -v git >/dev/null 2>&1; then
    die "git is required (opendmo sync is built on it). Install it first: sudo apt install git"
fi

fetch() {
    # fetch <url> <out-file>
    if command -v curl >/dev/null 2>&1; then
        curl -fsSL "$1" -o "$2"
    elif command -v wget >/dev/null 2>&1; then
        wget -qO "$2" "$1"
    else
        die "curl or wget is required. Install one first: sudo apt install curl"
    fi
}

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT

if [[ -n "$BASE_URL" ]]; then
    # Payload-dir mode: office-internal base serving the release file set.
    BASE_URL="${BASE_URL%/}"
    say "Downloading $PAYLOAD_TARBALL from $BASE_URL ..."
    if ! fetch "$BASE_URL/$PAYLOAD_TARBALL" "$TMP_DIR/$PAYLOAD_TARBALL" || ! fetch "$BASE_URL/SHA256SUMS" "$TMP_DIR/SHA256SUMS"; then
        die "download failed from $BASE_URL — is the office payload server up?"
    fi
    say "Verifying checksum ..."
    (cd "$TMP_DIR" && grep " $PAYLOAD_TARBALL\$" SHA256SUMS | sha256sum --check --quiet -) ||
        die "checksum mismatch for $PAYLOAD_TARBALL — corrupted or tampered download, not installed"
    TARBALL_PATH="$TMP_DIR/$PAYLOAD_TARBALL"
else
    # Registry mode: the public npm registry serves the platform package.
    command -v openssl >/dev/null 2>&1 ||
        die "openssl is required to verify the download. Install it first: sudo apt install openssl"
    VERSION="${VERSION#v}"
    META_URL="$REGISTRY/$PLATFORM_PKG/${VERSION:-latest}"
    say "Resolving $PLATFORM_PKG ${VERSION:-latest} from $REGISTRY ..."
    fetch "$META_URL" "$TMP_DIR/meta.json" ||
        die "could not resolve $META_URL — bad --version, or no network? Offices with an internal payload server: set OPENDMO_INSTALL_URL."
    TARBALL_URL="$(grep -o '"tarball":"[^"]*"' "$TMP_DIR/meta.json" | head -1 | cut -d'"' -f4)"
    INTEGRITY="$(grep -o '"integrity":"sha512-[^"]*"' "$TMP_DIR/meta.json" | head -1 | cut -d'"' -f4)"
    [[ -n "$TARBALL_URL" && -n "$INTEGRITY" ]] || die "unexpected registry metadata at $META_URL"
    say "Downloading $TARBALL_URL ..."
    fetch "$TARBALL_URL" "$TMP_DIR/package.tgz" || die "download failed: $TARBALL_URL"
    say "Verifying checksum ..."
    COMPUTED="sha512-$(openssl dgst -sha512 -binary "$TMP_DIR/package.tgz" | base64 -w0)"
    [[ "$COMPUTED" == "$INTEGRITY" ]] ||
        die "checksum mismatch for $PLATFORM_PKG — corrupted or tampered download, not installed"
    TARBALL_PATH="$TMP_DIR/package.tgz"
fi

say "Installing to $INSTALL_DIR ..."
rm -rf "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
# Both sources carry one top-level dir (opendmo/ or package/) — strip it.
tar -xzf "$TARBALL_PATH" --strip-components=1 -C "$INSTALL_DIR"

# A wrapper, not a symlink: the binary resolves its assets (packs/, theme/,
# version) relative to dirname(process.execPath), which a symlink can break.
mkdir -p "$BIN_DIR"
printf '#!/bin/sh\nexec "%s/opendmo" "$@"\n' "$INSTALL_DIR" > "$WRAPPER"
chmod +x "$WRAPPER"

case ":$PATH:" in
    *":$BIN_DIR:"*) ;;
    *)
        # Both files: .bashrc for interactive shells, .profile for login shells
        # (root's .bashrc has an interactivity guard that skips non-interactive
        # `bash -lc`, and root's .profile lacks the ~/.local/bin block).
        for rc in "$HOME/.bashrc" "$HOME/.profile"; do
            if ! grep -qs 'PATH="\$HOME/.local/bin:\$PATH"' "$rc"; then
                printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$rc"
            fi
        done
        say "Added $BIN_DIR to PATH in ~/.bashrc and ~/.profile — open a new shell (or: source ~/.bashrc)."
        ;;
esac

VERSION_LINE="$("$WRAPPER" --version 2>/dev/null || true)"
say "Installed opendmo${VERSION_LINE:+ $VERSION_LINE} — verify with: opendmo --help"

if [[ -n "$JOIN_FILE" ]]; then
    say "Joining the office from $JOIN_FILE ..."
    "$WRAPPER" init --join "$JOIN_FILE" \
        ${EMPLOYEE:+--employee "$EMPLOYEE"} \
        ${NAME:+--name "$NAME"}
    say "Joined. Start working with: opendmo"
else
    say "Join your office with: opendmo init --join <office-join.yaml from your manager>"
fi
