#!/bin/bash

# ============================================
# DigiPoS Updater Script - Usage Instructions
# ============================================
#
# This script updates the DigiPoS application on the local machine.
#
# Usage:
#   sudo ./digipos_updater.sh [version] [access-code]
#
# Arguments:
#   version      (optional) - The app version to update to. Default is 'latest'.
#   access-code  (required) - Auth token used for secure downloads.
#
# Example:
#   sudo ./digipos_updater.sh latest abc123
#   sudo ./digipos_updater.sh 2.4.1 abc123
#
# Make sure this script is executable:
#   chmod +x digipos_updater.sh
#
# This script must be run with sudo or root privileges.
# ============================================

# DigiPoS Updater Script
# ----------------------
# - Checks and downloads the latest or specific version
# - Stops the app
# - Backs up current version
# - Replaces old version safely
# - Updates autostart script and re-enables cron
# - Restarts the app
# - Logs update events with rollback if failed

set -euo pipefail

SCRIPT_VERSION="1.0"
APP_VERSION="${1:-latest}"
ACCESS_CODE="${2:-}"

APP_NAME="engine_api"
DOWNLOAD_BASE_URL="https://apps.digitory.com"
DOWNLOAD_FILE_NAME="pos_engine"

# Directory structure
APP_ROOT_DIR="/opt/digitory"
APP_DIR="$APP_ROOT_DIR/$APP_NAME"
LOG_DIR="/var/log/digitory"
BACKUP_DIR="$APP_DIR/.backup_$(date +%Y%m%d_%H%M%S)"
UPDATER_LOG="$LOG_DIR/updater.log"

MARKER_FILE="$APP_DIR/._digipos"
AUTOSTART_SCRIPT="digipos_autostart.sh"
ZIP_PATH="$APP_ROOT_DIR/${DOWNLOAD_FILE_NAME}.zip"

CMD_STOP="./bin/$APP_NAME stop"
CMD_START="./bin/$APP_NAME daemon"
CMD_PID="./bin/$APP_NAME pid"

mkdir -p "$LOG_DIR"

# Logs messages to both terminal and installer log
log() {
    ts=$(date "+%Y-%m-%d %H:%M:%S")
    mkdir -p "$LOG_DIR"
    echo "[$ts] $1"
    echo "[$ts] $1" >> "$UPDATER_LOG"
}

# Checks if the application is running by validating the PID
is_running() {
    local pid
    pid=$($CMD_PID 2>/dev/null)

    if [[ -z "$pid" ]]; then
        return 1 # PID is empty
    fi

    if ps -p "$pid" >/dev/null 2>&1; then
        return 0 # Process exists
    else
        return 1 # Process does not exist
    fi
}

# Stop the running application and ensure it shuts down
stop_app() {
    log "🔻 Stopping application..."
    $CMD_STOP || log "⚠️ Warning: stop command failed or not needed"

    # Retry loop to allow app to stop gracefully
    for i in {1..5}; do
        if ! is_running; then
            log "✅ Application stopped."
            return
        fi
        log "⏳ Waiting for app to stop... (attempt $i)"
        sleep 3
    done

    if is_running; then
        log "❌ Application did not stop after retries. Exiting."
        exit 1
    fi
}

# Backup the existing application files before update
backup_current_app() {
    mkdir -p "$BACKUP_DIR"
    cp -r "$APP_DIR"/* "$BACKUP_DIR" || log "⚠️ Partial backup created."
    log "📦 Backup created at $BACKUP_DIR"
}

# Download and extract the new version of the application
# Moves extracted contents to the main application directory
download_and_install_app() {
    log "⬇️  Downloading application version $APP_VERSION..."
    curl -fsSL "$DOWNLOAD_BASE_URL/prod/${DOWNLOAD_FILE_NAME}@${APP_VERSION}.zip?code=$ACCESS_CODE&isv=$SCRIPT_VERSION" -o $ZIP_PATH
    unzip -q -o "$ZIP_PATH" -d "$APP_ROOT_DIR"
    chmod +x "$APP_DIR/bin/$APP_NAME"
    rm -rf "$ZIP_PATH"
    log "✅ Application installed."
}

# Downloads the autostart script and makes it executable
fetch_autostart_script() {
    curl -fsSL "$DOWNLOAD_BASE_URL/scripts/$AUTOSTART_SCRIPT?code=$ACCESS_CODE&isv=$SCRIPT_VERSION" -o "$APP_ROOT_DIR/$AUTOSTART_SCRIPT"
    chmod +x "$APP_ROOT_DIR/$AUTOSTART_SCRIPT"
    log "Autostart script downloaded."
}

# Adds a cron job to ensure the app auto-starts periodically
update_crontab_autostart() {
    local cron_line="*/5 * * * * cd $APP_ROOT_DIR && ./$AUTOSTART_SCRIPT >> $UPDATER_LOG 2>&1"

    if ! crontab -l 2>/dev/null | grep -Fq "$cron_line"; then
        (crontab -l 2>/dev/null; echo "$cron_line") | crontab -
        log "✅ Autostart cron job added."
    else
        log "ℹ️  Autostart cron job already exists."
    fi

    log "🛠️  Autostart cron setup complete."
}

# Start the updated application and verify if it launched successfully
start_app() {
    log "🚀 Starting application..."
    cd "$APP_DIR"
    if $CMD_START >> "$UPDATER_LOG" 2>&1; then
        pid=$($CMD_PID 2>/dev/null || true)
        if [[ -n "$pid" ]]; then
            log "✅ Application started. PID: $pid"
        else
            log "⚠️ Application start issued, but PID not found."
        fi
    else
        log "❌ Failed to start application. Initiating rollback..."
        rollback_app
        exit 1
    fi
}

# Rollback the app to previous backup in case of failed update
rollback_app() {
    log "♻️  Rolling back to previous version from backup..."
    if [[ -d "$BACKUP_DIR" ]]; then
        rm -rf "${APP_DIR:?}/*"
        cp -r "$BACKUP_DIR"/* "$APP_DIR/"
        log "✅ Rollback complete. Attempting to restart original app."
        if $CMD_START >> "$UPDATER_LOG" 2>&1; then
            log "✅ Original application restored and restarted."
        else
            log "❌ Rollback application failed to start. Manual check required."
        fi
    else
        log "❌ No backup found. Cannot rollback."
    fi
}

# Update marker file with latest update metadata
update_marker_file() {
    local timestamp device_id hostname
    timestamp=$(date --iso-8601=seconds)
    device_id=$(cat /etc/machine-id 2>/dev/null)
    hostname=$(hostname)

    {
        echo "last_updated_at=$timestamp"
        echo "last_updated_by=updater"
        echo "device_id=$device_id"
        echo "hostname=$hostname"
        echo "script_version=$SCRIPT_VERSION"
        echo "app_version=$APP_VERSION"
    } >> "$MARKER_FILE"

    log "📘 Marker file updated."
}

# Main function wrapping full update flow
main() {
    cd "$APP_DIR"
    log "===== DigiPoS Update Started ====="
    stop_app
    backup_current_app
    download_and_install_app
    fetch_autostart_script
    update_crontab_autostart
    start_app
    update_marker_file
    log "✅ DigiPoS updated to version $APP_VERSION."
}

main "$@"

