#!/bin/bash
# On-premise MariaDB upgrade script for Debian/Ubuntu (repository-based)
# Called by replication-manager during rolling upgrade via SSH.
# The rolling upgrade flow is: maintenance on → stop → upgrade → start → rejoin → maintenance off
#
# Required environment (set by repman via GetSshEnv):
#   REPLICATION_MANAGER_USER, REPLICATION_MANAGER_PASSWORD
#   REPLICATION_MANAGER_URL, REPLICATION_MANAGER_CLUSTER_NAME
#   REPLICATION_MANAGER_HOST_NAME, REPLICATION_MANAGER_HOST_PORT
#   REPLICATION_MANAGER_HOST_USER, REPLICATION_MANAGER_HOST_PASSWORD
#
# Optional:
#   REPLICATION_MANAGER_DB_VERSION_TARGET  — target MariaDB version (e.g. "11.8")
#   REPLICATION_MANAGER_FORCE_CONFIG       — "true" to overwrite user-edited my.cnf

set -euo pipefail

function help {
    echo "Required Environment:" >&2
    echo "  REPLICATION_MANAGER_USER" >&2
    echo "  REPLICATION_MANAGER_PASSWORD" >&2
    echo "  REPLICATION_MANAGER_URL" >&2
    echo "  REPLICATION_MANAGER_CLUSTER_NAME" >&2
    echo "  REPLICATION_MANAGER_HOST_NAME" >&2
    echo "  REPLICATION_MANAGER_HOST_PORT" >&2
}

[ -z "${REPLICATION_MANAGER_USER:-}" ] && help && exit 1
[ -z "${REPLICATION_MANAGER_PASSWORD:-}" ] && help && exit 1
[ -z "${REPLICATION_MANAGER_URL:-}" ] && help && exit 1
[ -z "${REPLICATION_MANAGER_CLUSTER_NAME:-}" ] && help && exit 1
[ -z "${REPLICATION_MANAGER_HOST_NAME:-}" ] && help && exit 1
[ -z "${REPLICATION_MANAGER_HOST_PORT:-}" ] && help && exit 1

LOG_TAG="[repman-upgrade]"

log_info()  { echo "$LOG_TAG INFO: $*"; }
log_warn()  { echo "$LOG_TAG WARN: $*" >&2; }
log_error() { echo "$LOG_TAG ERROR: $*" >&2; }

########################
# API Helper
########################

# --no-check-certificate: repman typically uses self-signed certs for internal API.
# Set REPLICATION_MANAGER_WGET_OPTS to override (e.g. "--ca-certificate=/path/to/ca.pem").
GET="wget -q ${REPLICATION_MANAGER_WGET_OPTS:---no-check-certificate} -O- --header Content-Type:application/json"
AUTH_DATA="{\"username\": \"$REPLICATION_MANAGER_USER\", \"password\": \"$REPLICATION_MANAGER_PASSWORD\"}"
TOKEN=$($GET --post-data "$AUTH_DATA" --header Accept:text/html "$REPLICATION_MANAGER_URL/api/login") || {
    log_error "Failed to authenticate with replication-manager"
    exit 1
}

function get {
    $GET --header Accept:application/json --header "Authorization: Bearer $TOKEN" "$@"
}

########################
# Detect current version
########################

CURRENT_VERSION=""
if command -v mariadbd >/dev/null 2>&1; then
    CURRENT_VERSION=$(mariadbd --version 2>/dev/null | grep -oP 'Ver \K[0-9]+\.[0-9]+\.[0-9]+' || true)
elif command -v mysqld >/dev/null 2>&1; then
    CURRENT_VERSION=$(mysqld --version 2>/dev/null | grep -oP 'Ver \K[0-9]+\.[0-9]+\.[0-9]+' || true)
fi

if [ -z "$CURRENT_VERSION" ]; then
    # Try dpkg
    CURRENT_VERSION=$(dpkg -l 'mariadb-server*' 2>/dev/null | awk '/^ii.*mariadb-server/ {print $3}' | head -1 | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+' || true)
fi

log_info "Current MariaDB version: ${CURRENT_VERSION:-unknown}"

########################
# Determine target version
########################

# Target can come from env var or from repman API (prov-db-docker-img often contains the version)
# Target version is parsed from prov-db-docker-img (e.g. "mariadb:11.8" → "11.8")
# exported by repman as REPLICATION_MANAGER_DB_DOCKER_IMG
TARGET_VERSION=""
if [ -n "${REPLICATION_MANAGER_DB_DOCKER_IMG:-}" ]; then
    TARGET_VERSION=$(echo "$REPLICATION_MANAGER_DB_DOCKER_IMG" | grep -oP ':\K[0-9]+\.[0-9]+[0-9.]*' || true)
fi

if [ -z "$TARGET_VERSION" ]; then
    log_error "No target version found in REPLICATION_MANAGER_DB_DOCKER_IMG"
    exit 1
fi

# Extract major.minor for repository setup (e.g. "11.8" from "11.8.1")
TARGET_MAJOR_MINOR=$(echo "$TARGET_VERSION" | grep -oP '^[0-9]+\.[0-9]+')

log_info "Target MariaDB version: $TARGET_VERSION (repo: $TARGET_MAJOR_MINOR)"

########################
# Version comparison
########################

CURRENT_MAJOR_MINOR=$(echo "$CURRENT_VERSION" | grep -oP '^[0-9]+\.[0-9]+' || true)

if [ "$CURRENT_VERSION" = "$TARGET_VERSION" ]; then
    log_info "Already at target version $TARGET_VERSION, nothing to upgrade"
    exit 0
fi

if [ -n "$CURRENT_MAJOR_MINOR" ] && [ "$CURRENT_MAJOR_MINOR" = "$TARGET_MAJOR_MINOR" ]; then
    log_info "Minor upgrade: $CURRENT_VERSION → $TARGET_VERSION"
    UPGRADE_TYPE="minor"
else
    log_info "Major upgrade: $CURRENT_VERSION → $TARGET_VERSION"
    UPGRADE_TYPE="major"
fi

########################
# Pre-upgrade checks
########################

# Ensure MariaDB is stopped (rolling restart should have stopped it already)
if systemctl is-active --quiet mariadb 2>/dev/null || systemctl is-active --quiet mysql 2>/dev/null; then
    log_warn "MariaDB is still running, stopping before upgrade"
    systemctl stop mariadb 2>/dev/null || systemctl stop mysql 2>/dev/null || true
    sleep 2
fi

# Check disk space (need at least 1GB free for upgrade)
FREE_SPACE_MB=$(df -m /usr 2>/dev/null | awk 'NR==2 {print $4}')
if [ -n "$FREE_SPACE_MB" ] && [ "$FREE_SPACE_MB" -lt 1024 ]; then
    log_error "Insufficient disk space: ${FREE_SPACE_MB}MB free, need at least 1024MB"
    exit 1
fi

########################
# Update repository
########################

log_info "Configuring MariaDB $TARGET_MAJOR_MINOR repository"

# Repository info comes from db_distributions.json (tag-filtered, exported by repman).
# Falls back to auto-detection if not set.
REPO_BASE_URL="${REPLICATION_MANAGER_DB_REPO_BASE_URL:-https://mirror.mariadb.org/repo}"
REPO_KEY_URL="${REPLICATION_MANAGER_DB_REPO_KEY_URL:-https://mariadb.org/mariadb_release_signing_key.pgp}"

# Auto-detect OS details from the host
if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS_ID="${ID}"
    OS_CODENAME="${VERSION_CODENAME:-$(lsb_release -cs 2>/dev/null || echo 'bookworm')}"
else
    OS_ID="debian"
    OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "bookworm")
fi

REPO_URL="${REPO_BASE_URL}/${TARGET_MAJOR_MINOR}/${OS_ID}"
REPO_FILE="/etc/apt/sources.list.d/mariadb.list"

# Import signing key if not present
if ! apt-key list 2>/dev/null | grep -qi mariadb; then
    log_info "Importing MariaDB signing key"
    wget -qO- "$REPO_KEY_URL" | gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg 2>/dev/null || \
    wget -qO- "$REPO_KEY_URL" | apt-key add - 2>/dev/null || true
fi

cat > "$REPO_FILE" <<EOF
# MariaDB $TARGET_MAJOR_MINOR repository — managed by replication-manager
deb $REPO_URL $OS_CODENAME main
EOF

log_info "Repository configured: $REPO_URL $OS_CODENAME"

########################
# Upgrade packages
########################

log_info "Updating package index"
apt-get update -qq

log_info "Upgrading MariaDB packages to ${TARGET_VERSION}"

# Pin to the exact target version if it has a patch component (e.g. 11.8.6),
# otherwise install the latest available in the repo (e.g. 11.8).
APT_VERSION=""
if [[ "$TARGET_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    # Check if the exact version is available in the repo
    APT_CANDIDATE=$(apt-cache madison mariadb-server 2>/dev/null | grep "$TARGET_VERSION" | head -1 | awk '{print $3}')
    if [[ -n "$APT_CANDIDATE" ]]; then
        APT_VERSION="=${APT_CANDIDATE}"
        log_info "Pinning to version: $APT_CANDIDATE"
    else
        log_warn "Exact version $TARGET_VERSION not found in repo, installing latest in $TARGET_MAJOR_MINOR series"
    fi
fi

DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
    "mariadb-server${APT_VERSION}" "mariadb-client${APT_VERSION}" mariadb-backup 2>&1 | while read -r line; do
    log_info "apt: $line"
done

# Verify new version
NEW_VERSION=""
if command -v mariadbd >/dev/null 2>&1; then
    NEW_VERSION=$(mariadbd --version 2>/dev/null | grep -oP 'Ver \K[0-9]+\.[0-9]+\.[0-9]+' || true)
fi

if [ -z "$NEW_VERSION" ]; then
    log_error "Failed to detect MariaDB version after upgrade"
    exit 1
fi

log_info "Upgraded to MariaDB $NEW_VERSION"

########################
# Deploy config from repman
########################

log_info "Fetching configuration from replication-manager"
get "$REPLICATION_MANAGER_URL/api/clusters/$REPLICATION_MANAGER_CLUSTER_NAME/servers/$REPLICATION_MANAGER_HOST_NAME/$REPLICATION_MANAGER_HOST_PORT/config" > /tmp/config.tar.gz
if [ $? -eq 0 ] && [ -s /tmp/config.tar.gz ]; then
    mkdir -p /tmp/bootstrap
    tar xzf /tmp/config.tar.gz -C /tmp/bootstrap

    # Preserve user-edited my.cnf unless forced
    if [ -f /etc/mysql/my.cnf ]; then
        first_line=$(head -n 1 /etc/mysql/my.cnf)
        line_count=$(wc -l < /etc/mysql/my.cnf)
        if [[ $first_line != '# Generated by Signal18'* ]] && (( line_count > 1 )) && [ "${REPLICATION_MANAGER_FORCE_CONFIG:-}" != "true" ]; then
            cp /etc/mysql/my.cnf /etc/mysql/my.cnf.pre-upgrade
            log_info "Preserved existing my.cnf as my.cnf.pre-upgrade"
        fi
    fi

    chown -R mysql:mysql /tmp/bootstrap/data/.system 2>/dev/null || true
    cp -rpn /tmp/bootstrap/data/.system /var/lib/mysql/ 2>/dev/null || true
    cp -r /tmp/bootstrap/etc/mysql/* /etc/mysql/ 2>/dev/null || true

    rm -rf /tmp/config.tar.gz /tmp/bootstrap
    log_info "Configuration deployed"
else
    log_warn "Failed to fetch config from repman, starting with existing config"
fi

########################
# Start MariaDB
########################

log_info "Starting MariaDB $NEW_VERSION"
systemctl start mariadb 2>/dev/null || systemctl start mysql 2>/dev/null || {
    log_error "Failed to start MariaDB after upgrade"
    exit 1
}

# Wait for MariaDB to be ready
for i in $(seq 1 30); do
    if mariadb -u"${REPLICATION_MANAGER_HOST_USER:-root}" -p"${REPLICATION_MANAGER_HOST_PASSWORD:-$MYSQL_ROOT_PASSWORD}" -e "SELECT 1" >/dev/null 2>&1; then
        break
    fi
    sleep 1
done

########################
# Run mariadb-upgrade
########################

log_info "Running mariadb-upgrade"
if command -v mariadb-upgrade >/dev/null 2>&1; then
    mariadb-upgrade \
        -u"${REPLICATION_MANAGER_HOST_USER:-root}" \
        -p"${REPLICATION_MANAGER_HOST_PASSWORD:-$MYSQL_ROOT_PASSWORD}" \
        --force 2>&1 | while read -r line; do
        log_info "upgrade: $line"
    done
elif command -v mysql_upgrade >/dev/null 2>&1; then
    mysql_upgrade \
        -u"${REPLICATION_MANAGER_HOST_USER:-root}" \
        -p"${REPLICATION_MANAGER_HOST_PASSWORD:-$MYSQL_ROOT_PASSWORD}" \
        --force 2>&1 | while read -r line; do
        log_info "upgrade: $line"
    done
else
    log_warn "Neither mariadb-upgrade nor mysql_upgrade found, skipping"
fi

########################
# Update repman CLI
########################

MONITOR_VERSION=$(get "$REPLICATION_MANAGER_URL/api/version" 2>/dev/null || true)
CURRENT_CLI_VERSION=$(cat version.txt 2>/dev/null || echo "0.0.0")

if [ -n "$MONITOR_VERSION" ] && [ "$MONITOR_VERSION" != "$CURRENT_CLI_VERSION" ]; then
    log_info "Upgrading replication-manager-cli to $MONITOR_VERSION"
    get "$REPLICATION_MANAGER_URL/static/configurator/bin/replication-manager-cli" > /tmp/replication-manager-cli
    if [ $? -eq 0 ] && [ -s /tmp/replication-manager-cli ]; then
        cp /tmp/replication-manager-cli /usr/bin/replication-manager-cli
        chmod +x /usr/bin/replication-manager-cli
        echo "$MONITOR_VERSION" > version.txt
    fi
    rm -f /tmp/replication-manager-cli
fi

log_info "Upgrade complete: $CURRENT_VERSION → $NEW_VERSION"
