#!/bin/bash
#
# whatap-infra tarball installer
# Supports: CentOS/RHEL 7+, Ubuntu 16.04+, Debian 9+, SUSE 12+, Amazon Linux 2+
#
# Usage: ./install.sh [--prefix /custom/path]
#
# Default prefix: /usr/whatap/infra
#

set -e

META_DIR="/etc/whatap"
META_FILE="${META_DIR}/infra.meta"
PREFIX=""
PREFIX_EXPLICIT=false
LICENSE=""
WHATAP_HOST=""
WHATAP_PORT=""

# Safe meta file parser — reads only allowed keys, no source/eval
read_meta() {
    local file="$1"
    if [ ! -f "$file" ]; then
        return 1
    fi
    # Validate ownership (must be root-owned)
    local file_owner
    file_owner=$(stat -c '%u' "$file" 2>/dev/null || echo "unknown")
    if [ "$file_owner" != "0" ]; then
        echo "  WARNING: Meta file $file is not owned by root (uid=$file_owner), ignoring"
        return 1
    fi
    META_INSTALL_PREFIX=$(grep '^INSTALL_PREFIX=' "$file" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'")
    META_INSTALL_VERSION=$(grep '^INSTALL_VERSION=' "$file" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'")
    META_INSTALL_DATE=$(grep '^INSTALL_DATE=' "$file" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'")
    META_INSTALL_ARCH=$(grep '^INSTALL_ARCH=' "$file" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'")
    META_INIT_SYSTEM=$(grep '^INIT_SYSTEM=' "$file" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'")
    # Validate PREFIX is absolute path
    case "$META_INSTALL_PREFIX" in
        /*) ;; # OK — absolute path
        *)
            echo "  WARNING: Invalid INSTALL_PREFIX in meta file, ignoring"
            META_INSTALL_PREFIX=""
            return 1
            ;;
    esac
    return 0
}

write_meta() {
    mkdir -p "$META_DIR"
    cat > "$META_FILE" <<METAEOF
INSTALL_PREFIX="${PREFIX}"
INSTALL_VERSION="${INSTALL_VERSION}"
INSTALL_DATE="$(date '+%Y-%m-%dT%H:%M:%S%z')"
INSTALL_ARCH="${INSTALL_ARCH}"
INIT_SYSTEM="${INIT_SYSTEM}"
METAEOF
    chmod 0644 "$META_FILE"
    chown root:root "$META_FILE" 2>/dev/null || true
}

# Append key=value to conf file only if key does not already exist
# Skips commented lines and tolerates whitespace around key/=
ensure_conf_key() {
    local file="$1" key="$2" value="$3"
    if [ ! -f "$file" ]; then
        touch "$file"
        chmod 0644 "$file"
    fi
    if ! grep -q "^[[:space:]]*${key}[[:space:]]*=" "$file" 2>/dev/null; then
        printf '%s=%s\n' "$key" "$value" >> "$file"
    fi
}

print_usage() {
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  --prefix PATH          Installation directory (default: /usr/whatap/infra)"
    echo "  --license LICENSE      Set license key in whatap.conf"
    echo "  --whatap_host HOST     Set whatap server host in whatap.conf"
    echo "  --whatap_port PORT     Set whatap server port in whatap.conf"
    echo "  --help                 Show this help message"
}

while [ $# -gt 0 ]; do
    case "$1" in
        --prefix)
            if [ -z "$2" ] || [ "${2#--}" != "$2" ]; then
                echo "Error: --prefix requires a value"
                exit 1
            fi
            PREFIX="$2"
            PREFIX_EXPLICIT=true
            shift 2
            ;;
        --license)
            if [ -z "$2" ] || [ "${2#--}" != "$2" ]; then
                echo "Error: --license requires a value"
                exit 1
            fi
            LICENSE="$2"
            shift 2
            ;;
        --whatap_host)
            if [ -z "$2" ] || [ "${2#--}" != "$2" ]; then
                echo "Error: --whatap_host requires a value"
                exit 1
            fi
            WHATAP_HOST="$2"
            shift 2
            ;;
        --whatap_port)
            if [ -z "$2" ] || [ "${2#--}" != "$2" ]; then
                echo "Error: --whatap_port requires a value"
                exit 1
            fi
            WHATAP_PORT="$2"
            if ! [[ "$WHATAP_PORT" =~ ^[0-9]+$ ]] || [ "$WHATAP_PORT" -lt 1 ] || [ "$WHATAP_PORT" -gt 65535 ]; then
                echo "Error: --whatap_port requires a valid port number (1-65535)"
                exit 1
            fi
            shift 2
            ;;
        --help)
            print_usage
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            print_usage
            exit 1
            ;;
    esac
done

# Check root (early — needed before reading meta)
if [ "$(id -u)" -ne 0 ]; then
    echo "Error: This script must be run as root"
    exit 1
fi

# Determine install mode and PREFIX
INSTALL_MODE="fresh"
if read_meta "$META_FILE"; then
    # Existing installation detected
    if [ "$PREFIX_EXPLICIT" = true ]; then
        PREFIX="${PREFIX%/}"
        if [ -n "$META_INSTALL_PREFIX" ] && [ "$PREFIX" != "$META_INSTALL_PREFIX" ]; then
            echo "  WARNING: --prefix ($PREFIX) differs from existing installation ($META_INSTALL_PREFIX)"
            echo "  Proceeding with --prefix value. Old installation at $META_INSTALL_PREFIX will NOT be removed."
        fi
    else
        PREFIX="${META_INSTALL_PREFIX}"
    fi
    INSTALL_MODE="update"
    echo "=== whatap-infra installer (update mode) ==="
    echo "  Existing version : ${META_INSTALL_VERSION:-unknown}"
    echo "  Existing path    : ${META_INSTALL_PREFIX}"
else
    # Fresh install
    if [ -z "$PREFIX" ]; then
        PREFIX="/usr/whatap/infra"
    fi
    PREFIX="${PREFIX%/}"
    echo "=== whatap-infra installer (fresh install) ==="
fi

echo "Install prefix: $PREFIX"
echo ""

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CONF_DIR="$PREFIX/conf"

# Detect architecture from binary
INSTALL_ARCH=$(uname -m)
case "$INSTALL_ARCH" in
    x86_64) INSTALL_ARCH="amd64" ;;
    aarch64) INSTALL_ARCH="arm64" ;;
esac

# Read version from tarball conf/VERSION
INSTALL_VERSION=""
if [ -f "$SCRIPT_DIR/conf/VERSION" ]; then
    INSTALL_VERSION=$(cat "$SCRIPT_DIR/conf/VERSION" 2>/dev/null | head -1 | tr -d '[:space:]')
fi

# Detect init system by checking PID 1
detect_init_system() {
    local pid1_comm
    pid1_comm=$(cat /proc/1/comm 2>/dev/null || echo "")

    if [ "$pid1_comm" = "systemd" ]; then
        echo "systemd"
    elif [ "$pid1_comm" = "init" ]; then
        # Could be upstart or sysvinit
        if /sbin/init --version 2>&1 | grep -q upstart; then
            echo "upstart"
        else
            echo "sysvinit"
        fi
    else
        # Fallback: container or unknown — check for systemctl availability and PID 1
        if command -v systemctl >/dev/null 2>&1 && [ "$(cat /proc/1/comm 2>/dev/null)" = "systemd" ]; then
            echo "systemd"
        else
            echo "sysvinit"
        fi
    fi
}

INIT_SYSTEM=$(detect_init_system)

# SELinux / AppArmor warning
if command -v getenforce >/dev/null 2>&1; then
    SELINUX_STATUS=$(getenforce 2>/dev/null || echo "Disabled")
    if [ "$SELINUX_STATUS" = "Enforcing" ]; then
        echo "  WARNING: SELinux is Enforcing. If the agent fails to start,"
        echo "  you may need to create a policy or set permissive mode for it."
        echo ""
    fi
fi

# Stop existing services if updating
if [ "$INSTALL_MODE" = "update" ]; then
    echo "[0/5] Stopping existing services for update..."
    if [ "$INIT_SYSTEM" = "systemd" ]; then
        systemctl stop whatap-infra 2>/dev/null || true
    else
        service whatap-infra stop 2>/dev/null || true
    fi
    echo "  - Services stopped"
fi

# Create directories
echo "[1/5] Creating directories..."
mkdir -p "$PREFIX"
mkdir -p "$CONF_DIR"

# Copy binary and files
echo "[2/5] Installing files..."
install -m 0755 "$SCRIPT_DIR/whatap_infrad" "$PREFIX/whatap_infrad"

if [ -f "$SCRIPT_DIR/infra_agent_patch.sh" ]; then
    install -m 0755 "$SCRIPT_DIR/infra_agent_patch.sh" "$PREFIX/infra_agent_patch.sh"
fi

if [ -f "$SCRIPT_DIR/conf/VERSION" ]; then
    install -m 0644 "$SCRIPT_DIR/conf/VERSION" "$CONF_DIR/VERSION"
fi

if [ -f "$SCRIPT_DIR/ChangeLog.txt" ]; then
    install -m 0644 "$SCRIPT_DIR/ChangeLog.txt" "$PREFIX/ChangeLog.txt"
fi

# Preserve existing whatap.conf if present
if [ -f "$CONF_DIR/whatap.conf" ]; then
    echo "  - Existing whatap.conf preserved"
fi

# Configure whatap.conf (only add keys that don't already exist)
WHATAP_CONF="$CONF_DIR/whatap.conf"
if [ -n "$LICENSE" ]; then
    ensure_conf_key "$WHATAP_CONF" "license" "$LICENSE"
    echo "  - license configured"
fi
if [ -n "$WHATAP_HOST" ]; then
    ensure_conf_key "$WHATAP_CONF" "whatap.server.host" "$WHATAP_HOST"
    echo "  - whatap.server.host configured"
fi
if [ -n "$WHATAP_PORT" ]; then
    ensure_conf_key "$WHATAP_CONF" "whatap.server.port" "$WHATAP_PORT"
    echo "  - whatap.server.port configured"
fi
ensure_conf_key "$WHATAP_CONF" "createdtime" "$(date +%s%N)"

# Install service
echo "[3/5] Installing service files (both systemd + SysV, registering $INIT_SYSTEM)..."

# Always create systemd unit (based on centos8/9 packaging)
mkdir -p /etc/systemd/system
cat > /etc/systemd/system/whatap-infra.service <<SERVICEEOF
[Unit]
Documentation=https://docs.whatap.io/server/introduction
Description=Whatap Server Performance Monitoring Agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment="MALLOC_ARENA_MAX=2"
Environment="WHATAP_HOME=${CONF_DIR}"
Environment="WHATAP_PID_FILE=${CONF_DIR}/whatap_infrad.pid"

ExecStart=${PREFIX}/whatap_infrad watchdog

KillMode=control-group
KillSignal=SIGTERM
SendSIGKILL=yes
TimeoutStopSec=30

LimitNOFILE=65536
OOMScoreAdjust=-100

StandardOutput=null
StandardError=journal

[Install]
WantedBy=multi-user.target
SERVICEEOF
echo "  - systemd unit installed"

# Always create SysV init script (with systemd redirect guard)
cat > /etc/init.d/whatap-infra <<'INITEOF'
#!/bin/sh
# chkconfig: 2345 90 10
# description: whatap infra monitoring agent
### BEGIN INIT INFO
# Provides:          whatap-infra
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start whatap-infra daemon
### END INIT INFO

if [ "$(cat /proc/1/comm 2>/dev/null)" = "systemd" ]; then
    if [ -n "$1" ]; then
        exec systemctl "$1" whatap-infra
    fi
    echo "Usage: $0 {start|stop|restart|status}" >&2
    exit 1
fi

set -e

NAME=whatap_infrad
WHATAP_BASE=__PREFIX__
DAEMON=$WHATAP_BASE/$NAME
DESC="whatap infra"
SCRIPT_NAME="whatap-infra"
export WHATAP_HOME=$WHATAP_BASE/conf
export GOTRACEBACK=all

if [ ! -f "$WHATAP_HOME/whatap.conf" ] ; then
    exit 0
fi

PID=$WHATAP_BASE/conf/$NAME.pid
export WHATAP_PID_FILE="$PID"

RETRY=15

export PATH="${PATH:+$PATH:}$WHATAP_BASE"

start() {
    echo "Starting $DESC..."
    if [ -f "$PID" ] && kill -0 "$(cat "$PID")" 2>/dev/null; then
        echo "$NAME already running"
        return 0
    fi
    $DAEMON &
    echo $! > "$PID"
    echo "$NAME started"
}

stop() {
    echo "Stopping $DESC..."
    if [ -f "$PID" ]; then
        kill "$(cat "$PID")" 2>/dev/null || true
        WAIT=0
        while [ $WAIT -lt $RETRY ] && kill -0 "$(cat "$PID")" 2>/dev/null; do
            sleep 1
            WAIT=$((WAIT+1))
        done
        if kill -0 "$(cat "$PID")" 2>/dev/null; then
            kill -9 "$(cat "$PID")" 2>/dev/null || true
        fi
        rm -f "$PID"
        echo "$NAME stopped"
    else
        echo "$NAME not running"
    fi
}

status() {
    if [ -f "$PID" ] && kill -0 "$(cat "$PID")" 2>/dev/null; then
        echo "$NAME is running (pid $(cat "$PID"))"
        return 0
    fi
    echo "$NAME is not running"
    return 3
}

case "$1" in
    start) start ;;
    stop) stop ;;
    restart|force-reload) stop; start ;;
    status) status ;;
    *) echo "Usage: $0 {start|stop|restart|status}" >&2; exit 1 ;;
esac

exit 0
INITEOF
sed -i "s|__PREFIX__|${PREFIX}|g" /etc/init.d/whatap-infra
chmod 755 /etc/init.d/whatap-infra
echo "  - SysV init script installed"

# Register only the detected init system
if [ "$INIT_SYSTEM" = "systemd" ]; then
    systemctl daemon-reload
    systemctl enable whatap-infra.service 2>/dev/null || true
    echo "  - systemd service enabled"
else
    # Register service: chkconfig (RHEL/CentOS) or update-rc.d (Debian/Ubuntu)
    if command -v chkconfig >/dev/null 2>&1; then
        chkconfig --add whatap-infra 2>/dev/null || true
        chkconfig whatap-infra on 2>/dev/null || true
    elif command -v update-rc.d >/dev/null 2>&1; then
        update-rc.d whatap-infra defaults 2>/dev/null || true
    fi
    echo "  - SysV init script registered"
fi

# Install updater service
echo "[4/5] Installing updater service..."
if [ -f "$PREFIX/infra_agent_patch.sh" ]; then
    # Always create systemd unit for updater
    mkdir -p /etc/systemd/system
    cat > /etc/systemd/system/whatap-updater.service <<UPDATERSERVICEEOF
[Unit]
Description=Whatap Updater
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=${PREFIX}/infra_agent_patch.sh ${PREFIX}/whatap.env
TimeoutStartSec=infinity

[Install]
WantedBy=multi-user.target
UPDATERSERVICEEOF
    echo "  - updater systemd unit installed"

    # Always create SysV init script for updater (with systemd redirect guard)
    cat > /etc/init.d/whatap-updater <<'UPDATERINITEOF'
#!/bin/sh
# chkconfig: - 91 9
# description: whatap infra agent updater
### BEGIN INIT INFO
# Provides:          whatap-updater
# Required-Start:    $network
# Required-Stop:
# Default-Start:
# Default-Stop:
# Short-Description: Whatap Updater
### END INIT INFO

if [ "$(cat /proc/1/comm 2>/dev/null)" = "systemd" ]; then
    if [ -n "$1" ]; then
        exec systemctl "$1" whatap-updater
    fi
    echo "Usage: $0 {start|stop|restart|status}" >&2
    exit 1
fi

UPDATER="__PREFIX__/infra_agent_patch.sh"
ENVFILE="__PREFIX__/whatap.env"
PIDFILE="/var/run/whatap-updater.pid"
LOG="/var/log/whatap-updater.log"

start() {
    if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
        echo "whatap-updater already running"
        return 0
    fi
    mkdir -p /var/run 2>/dev/null || true
    mkdir -p /var/log 2>/dev/null || true
    nohup setsid /bin/bash -c "
        echo \$\$ > '$PIDFILE'
        exec '$UPDATER' '$ENVFILE' >> '$LOG' 2>&1
        rc=\$?
        rm -f '$PIDFILE'
        exit \$rc
    " >/dev/null 2>&1 &
    echo "started"
}

stop() {
    if [ -f "$PIDFILE" ]; then
        kill -9 "$(cat "$PIDFILE")" 2>/dev/null || true
        rm -f "$PIDFILE"
        echo "stopped"
    else
        echo "not running"
    fi
}

status() {
    if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
        echo "running (pid $(cat "$PIDFILE"))"
        return 0
    fi
    echo "not running"
    return 3
}

case "$1" in
    start) start ;;
    stop) stop ;;
    restart|force-reload) stop; start ;;
    status) status ;;
    *) echo "Usage: $0 {start|stop|restart|status}"; exit 2 ;;
esac

exit 0
UPDATERINITEOF
    sed -i "s|__PREFIX__|${PREFIX}|g" /etc/init.d/whatap-updater
    chmod 755 /etc/init.d/whatap-updater
    echo "  - updater SysV init script installed"

    # Reload systemd if available so new unit is visible
    if [ "$INIT_SYSTEM" = "systemd" ]; then
        systemctl daemon-reload
    fi
    echo "  - updater service installed"
else
    echo "  - updater script not found, skipping"
fi

# Save install metadata to /etc/whatap/infra.meta
echo "[5/5] Saving meta information..."
write_meta
echo "  - Meta saved: $META_FILE"

# Remove legacy metadata file
rm -f "$PREFIX/.install_prefix"

echo ""
echo "Installation complete!"
echo ""
echo "  Install path : $PREFIX"
echo "  Version      : ${INSTALL_VERSION:-unknown}"
echo "  Config file  : $CONF_DIR/whatap.conf"
echo "  Init system  : $INIT_SYSTEM"
echo "  Meta file    : $META_FILE"
echo "  Service      : whatap-infra"
echo "  Mode         : $INSTALL_MODE"
echo ""
echo "Next steps:"
echo "  1. Edit $CONF_DIR/whatap.conf (set license and server host)"
echo "  2. Start the agent:"
if [ "$INIT_SYSTEM" = "systemd" ]; then
    echo "     systemctl start whatap-infra"
else
    echo "     service whatap-infra start"
fi
echo ""
