#!/bin/bash

# ================================================
# DigiPoS Installer Script - Usage Instructions
# ================================================
#
# This script sets up a fresh DigiPoS installation.
#
# Usage:
#   curl -fsSL "https://apps.digitory.com/scripts/digipos_installer.sh?code=ACCESS_CODE" -o digipos_installer.sh \
#     && chmod +x digipos_installer.sh \
#     && ./digipos_installer.sh [version] [access-code]
#
# Arguments:
#   version      (optional) - The DigiPoS app version to install (default: latest)
#   access-code  (required) - Auth token used for secure downloads
# Example:
#   curl -fsSL "https://apps.digitory.com/scripts/digipos_installer.sh?code=abc123" -o digipos_installer.sh \
#     && chmod +x digipos_installer.sh \
#     && ./digipos_installer.sh latest abc123 

# OR if downloaded manually:
#   chmod +x digipos_installer.sh
#   sudo ./digipos_installer.sh latest abc123
#
# This script must be run with sudo or root privileges.
#
# ================================================
# What This Script Does:
# --------------------------------
# - Creates application, data, log, and backup folders
# - Downloads DigiPoS and installs it into /opt/digitory
# - Generates a machine marker file for tracking
# - Fetches the autostart script and enables cron job
# - Fetches the updater script for future updates
# - Starts the DigiPoS application
# - Logs installation summary and status
# ================================================

set -euo pipefail

# Installer script version
SCRIPT_VERSION="1.0"
APP_VERSION="${1:-latest}"
ACCESS_CODE="${2:-}"

# Ensure access code is provided
if [[ -z "$ACCESS_CODE" ]]; then
    echo "❌ Error: Access code is required as the second argument."
    echo "Usage: ./digipos_installer.sh [version] <access-code>"
    exit 1
fi

APP_NAME="engine_api"
DOWNLOAD_BASE_URL="https://apps.digitory.com"
DOWNLOAD_FILE_NAME="pos_engine"
#INSTALL_SCRIPT_NAME="digipos_installer.sh"

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

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

CMD_START="./bin/$APP_NAME daemon"
CMD_PID="./bin/$APP_NAME pid"
CMD_VERSION="./bin/$APP_NAME version"

# 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"
}

# Prompts the user with a yes/no confirmation
prompt_confirm() {
    echo -n "$1 [y/N]: "
    read -r response
    [[ "$response" =~ ^[yY]$ ]]
}

# Creates required directories for app, data, logs, and backups
prepare_dirs() {
    mkdir -p "$APP_ROOT_DIR" "$APP_DIR" "$DATA_DIR" "$LOG_DIR" "$BACKUP_DIR"
    chown -R "$(whoami)" "$APP_DIR" "$DATA_DIR" "$BACKUP_DIR"
    log "Created application, data, log, and backup directories."
}

# Generates a marker file storing installation metadata
write_marker_file() {
    # Retrieve a stable device ID (from machine-id)
    device_id=$(cat /etc/machine-id 2>/dev/null)

    # ISO 8601 formatted timestamp
    timestamp=$(date --iso-8601=seconds)

    # Write metadata to marker file
    {
        echo "initialized_at=$timestamp"
        echo "installed_by=installer"
        echo "device_id=$device_id"
        echo "script_version=$SCRIPT_VERSION"
    } > "$MARKER_FILE"

    log "Marker file created at $MARKER_FILE."
}


# 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."
}

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

# Downloads and installs the application from the remote ZIP
# 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."
}
# Validates required tools are installed before continuing
prerequisites() {
    for cmd in curl unzip crontab; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            echo "Error: Required command '$cmd' is not installed." >&2
            exit 1
        fi
    done
    log "All prerequisites verified."
}

# 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
}


# Prints a summary of the installation result to the user and log
# Also deletes the installer script
print_installation_summary() {
    local status="$1"
    local pid="$2"
    local device_id="$3"
    local app_version="$4"

    # Get hostname for device name
    device_name=$(hostname)

    log "Application Status: $status"
    log "PID: $pid"
    log "Device ID: $device_id"
    log "Device Name: $device_name"
    log "Version: $app_version"
    log "Marker File: $MARKER_FILE"
    log "ℹ️  Refer to this Device ID or Name in the Admin App to enable the server."

    # Delete installer script if present
    if [[ -f "$0" ]]; then
        rm -- "$0"
    fi
}

# 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
        if is_running; then
            local pid
            pid=$($CMD_PID 2>/dev/null || true)
            log "✅ Application started. PID: $pid"
            
            device_id=$(grep '^device_id=' "$MARKER_FILE" | cut -d'=' -f2)
            app_version=$($CMD_VERSION 2>/dev/null || echo "unknown")
            print_installation_summary "✅ DigiPoS Installed Successfully!" "$pid" "$device_id" "$app_version"
        else
            log "⚠️ Application start issued, but process is not running."
            print_installation_summary "❌ DigiPoS Installation Failed (App Not Running)" "Not Found" "$device_id" "$app_version"
        fi
    else
        log "❌ Failed to start application"
        exit 1
    fi
}

# Entry point of the installer script
main() {
    if [[ "$EUID" -ne 0 ]]; then
        echo "🔁 Re-running installer with sudo..."
        exec sudo bash "$0" "$@"
    fi

    log "Starting DigiPoS installer..."
    prerequisites

    if [[ -f "$MARKER_FILE" ]]; then
        log "App already installed. Switching to updater."
        "$APP_DIR/$UPDATER_SCRIPT"
        rm -- "$0"
        exit 0
    fi

    prompt_confirm "Proceed with first-time installation?" || { log "Installation aborted."; rm -- "$0"; exit 1; }

    prepare_dirs
    fetch_autostart_script
    update_crontab_autostart
    fetch_updater
    download_and_install_app
    write_marker_file # Generate marker file
    start_app
}

main "$@"

