#!/bin/bash

# A robust installation script for Netmaker Desktop.
# This script must be run with sudo privileges.

# --- Script Configuration ---
# Exit on any error, undefined variable, or pipeline failure.
set -euo pipefail

# --- Global Constants ---
readonly VERSION="${1:-"latest"}"
readonly DAEMON_FILENAME="netmaker-desktop-daemon-linux-amd64"
readonly GUI_FILENAME="netmaker-desktop-gui-linux-amd64.zip"
readonly ICON_FILENAME="netmaker-desktop.png"

readonly BASE_URL="https://fileserver.netmaker.io/releases/download/${VERSION}"
readonly DAEMON_DOWNLOAD_URL="${BASE_URL}/${DAEMON_FILENAME}"
readonly GUI_DOWNLOAD_URL="${BASE_URL}/${GUI_FILENAME}"
readonly ICON_DOWNLOAD_URL="https://fileserver.netmaker.io/${ICON_FILENAME}"

readonly DAEMON_INSTALL_DIR="/usr/bin"
readonly GUI_INSTALL_DIR="/opt/NetmakerDesktop"
readonly ICON_INSTALL_DIR="/usr/share/icons/hicolor/scalable/apps"
readonly SHORTCUT_INSTALL_DIR="/usr/share/applications"
readonly SERVICE_INSTALL_DIR="/etc/systemd/system"

# --- Cache Configuration ---
# Directory to store cached files. This will persist across script runs.
readonly CACHE_DIR="/var/cache/netmaker-desktop"
# Duration for which a cached file is considered fresh (24 hours in seconds).
readonly CACHE_DURATION=$((24 * 60 * 60))

# --- State Variables ---
# Create a temporary directory and ensure it's cleaned up on exit.
TMP_DIR=$(mktemp -d)
trap cleanup EXIT

# --- Functions ---

# Cleans up the temporary directory created by the script.
cleanup() {
  log "Cleaning up temporary directory: $TMP_DIR"
  rm -rf "$TMP_DIR"
}

# Logs an informational message to stdout.
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] [INFO] $1"
}

# Logs an error message to stderr and exits the script.
error() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] [ERROR] $1 (line: $2)" >&2
  exit 1
}

# Ensures the cache directory exists and is writable.
ensure_cache_dir() {
    log "Ensuring cache directory exists at $CACHE_DIR..."
    mkdir -p "$CACHE_DIR" || error "Failed to create cache directory $CACHE_DIR. Check permissions." "$LINENO"
    log "Cache directory is ready."
}

# Checks for and installs required system dependencies.
check_dependencies() {
    log "Checking for required dependencies..."
    local PKG_MANAGER=""
    if command -v apt-get &>/dev/null; then PKG_MANAGER="apt-get";
    elif command -v dnf &>/dev/null; then PKG_MANAGER="dnf";
    elif command -v yum &>/dev/null; then PKG_MANAGER="yum";
    elif command -v pacman &>/dev/null; then PKG_MANAGER="pacman";
    else
        log "WARNING: Cannot detect a supported package manager (apt, dnf, yum, pacman)."
        log "Please ensure 'resolvconf' and 'wireguard-tools' are installed manually."
        command -v resolvconf &>/dev/null || error "resolvconf is not installed." "N/A"
        command -v wg &>/dev/null || error "wireguard-tools is not installed." "N/A"
        return
    fi

    local deps_to_install=()
    local resolvconf_pkg="resolvconf" && [[ "$PKG_MANAGER" == "pacman" ]] && resolvconf_pkg="openresolv"
    local wireguard_pkg="wireguard-tools"

    command -v resolvconf &>/dev/null || deps_to_install+=("$resolvconf_pkg")
    command -v wg &>/dev/null || deps_to_install+=("$wireguard_pkg")

    if [ ${#deps_to_install[@]} -gt 0 ]; then
        log "Missing dependencies: ${deps_to_install[*]}"
        log "Attempting to install with ${PKG_MANAGER}..."
        case "$PKG_MANAGER" in
            "apt-get") sudo apt-get update >/dev/null && sudo apt-get install -y "${deps_to_install[@]}" ;;
            "dnf"|"yum") sudo "$PKG_MANAGER" install -y "${deps_to_install[@]}" ;;
            "pacman") sudo pacman -Sy --noconfirm "${deps_to_install[@]}" ;;
        esac || error "Failed to install dependencies. Please install them manually." "$LINENO"
        log "Dependencies installed successfully."
    fi

    log "All dependencies satisfied."
}

# Downloads required files for Netmaker Desktop.
# Incorporates caching logic: if a file is in the cache and less than 24 hours old, it's reused.
download_files() {
    log "Downloading Netmaker Desktop assets (Version: ${VERSION})..."

    # Array of file information: "filename|download_url"
    local files=(
        "$DAEMON_FILENAME|$DAEMON_DOWNLOAD_URL"
        "$GUI_FILENAME|$GUI_DOWNLOAD_URL"
        "$ICON_FILENAME|$ICON_DOWNLOAD_URL"
    )

    for file_info in "${files[@]}"; do
        # Split the file_info string into FILENAME and DOWNLOAD_URL
        IFS='|' read -r FILENAME DOWNLOAD_URL <<< "$file_info"
        local CACHE_FILE_PATH="${CACHE_DIR}/${FILENAME}"

        # Check if the file exists in the cache and is still fresh
        if [ -f "$CACHE_FILE_PATH" ]; then
            # Get the modification time of the cached file in seconds since epoch
            local FILE_MOD_TIME=$(stat -c %Y "$CACHE_FILE_PATH")
            # Calculate the age of the file
            local CURRENT_TIME=$(date +%s)
            local FILE_AGE=$((CURRENT_TIME - FILE_MOD_TIME))

            if [ "$FILE_AGE" -lt "$CACHE_DURATION" ]; then
                log "Reusing cached file: $FILENAME (downloaded ${FILE_AGE} seconds ago)"
                # Copy the cached file to the temporary directory for installation
                cp "$CACHE_FILE_PATH" "${TMP_DIR}/${FILENAME}" || error "Failed to copy cached file $FILENAME to temporary directory." "$LINENO"
                continue # Skip download and move to the next file
            fi
        fi

        # If file is not cached or is stale, download it
        log "Downloading $FILENAME from $DOWNLOAD_URL..."
        curl --fail --location --silent --show-error -o "${TMP_DIR}/${FILENAME}" "$DOWNLOAD_URL" || error "Failed to download $FILENAME." "$LINENO"
        
        # Cache the newly downloaded file
        log "$FILENAME downloaded. Caching to $CACHE_DIR..."
        cp "${TMP_DIR}/${FILENAME}" "$CACHE_FILE_PATH" || error "Failed to cache $FILENAME. Check permissions for $CACHE_DIR." "$LINENO"
        log "$FILENAME cached successfully."
    done
    log "All assets downloaded/reused successfully."
}

# Uninstalls any previous Netmaker Desktop installations.
uninstall_previous() {
    log "Checking for and removing previous installations..."
    systemctl stop netmaker-desktop.service &>/dev/null || true
    systemctl disable netmaker-desktop.service &>/dev/null || true
    rm -f "${SERVICE_INSTALL_DIR}/netmaker-desktop.service"
    rm -f "${DAEMON_INSTALL_DIR}/netmaker-desktop-daemon"
    rm -rf "${GUI_INSTALL_DIR}"
    rm -f "${SHORTCUT_INSTALL_DIR}/netmaker-desktop.desktop"
    rm -f "${ICON_INSTALL_DIR}/${ICON_FILENAME}"
    log "Previous installation cleanup complete."
}

# Installs the downloaded application files to their respective directories.
install_files() {
    log "Installing application files..."

    # Install daemon
    mv "${TMP_DIR}/${DAEMON_FILENAME}" "${DAEMON_INSTALL_DIR}/netmaker-desktop-daemon" || error "Failed to move daemon to install directory." "$LINENO"
    chmod 755 "${DAEMON_INSTALL_DIR}/netmaker-desktop-daemon"

    # Install GUI
    mkdir -p "${GUI_INSTALL_DIR}" || error "Failed to create GUI install directory." "$LINENO"
    unzip -oq "${TMP_DIR}/${GUI_FILENAME}" -d "${GUI_INSTALL_DIR}" || error "Failed to unzip GUI." "$LINENO"
    chmod 755 "${GUI_INSTALL_DIR}/netmaker-desktop"

    # Install Icon
    mkdir -p "${ICON_INSTALL_DIR}" || error "Failed to create icon install directory." "$LINENO"
    mv "${TMP_DIR}/${ICON_FILENAME}" "${ICON_INSTALL_DIR}/${ICON_FILENAME}" || error "Failed to move icon to install directory." "$LINENO"
    chmod 644 "${ICON_INSTALL_DIR}/${ICON_FILENAME}"

    log "Application files installed."
}

# Sets up the systemd service for the Netmaker Desktop daemon.
setup_service() {
    log "Setting up systemd daemon service..."
    if ! command -v systemctl &>/dev/null; then
        log "WARNING: systemd not found. Skipping service installation."
        return
    fi

    cat <<EOF > "${SERVICE_INSTALL_DIR}/netmaker-desktop.service"
[Unit]
Description=Netmaker Desktop Daemon
Documentation=https://docs.netmaker.io
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=${DAEMON_INSTALL_DIR}/netmaker-desktop-daemon
Restart=on-failure
RestartSec=10s

[Install]
WantedBy=multi-user.target
EOF

    chmod 644 "${SERVICE_INSTALL_DIR}/netmaker-desktop.service"
    systemctl daemon-reload
    systemctl enable netmaker-desktop.service
    systemctl start netmaker-desktop.service
    log "Daemon service enabled and started."
}

# Installs desktop shortcuts and updates system caches.
install_shortcuts() {
    log "Installing desktop shortcut and icon..."
    cat <<EOF > "${SHORTCUT_INSTALL_DIR}/netmaker-desktop.desktop"
[Desktop Entry]
Name=Netmaker Desktop
Comment=A desktop client for the Netmaker WireGuard automation platform.
Exec=${GUI_INSTALL_DIR}/netmaker-desktop
Icon=${ICON_INSTALL_DIR}/${ICON_FILENAME}
Terminal=false
Type=Application
Categories=Network;
EOF

    chmod 644 "${SHORTCUT_INSTALL_DIR}/netmaker-desktop.desktop"
    
    log "Updating desktop and icon caches..."
    # Update databases to ensure the shortcut and icon appear in menus
    update-desktop-database -q "${SHORTCUT_INSTALL_DIR}" &>/dev/null || log "WARNING: update-desktop-database not found or failed."
    gtk-update-icon-cache -q -t "${ICON_INSTALL_DIR}" &>/dev/null || log "WARNING: gtk-update-icon-cache not found or failed."

    log "Desktop shortcut installed."
}

# Main function to orchestrate the installation process.
main() {
    # Check for root privileges
    if [[ "$EUID" -ne 0 ]]; then
      error "This script must be run as root. Please use sudo." "$LINENO"
    fi

    log "Starting Netmaker Desktop installation..."

    check_dependencies
    uninstall_previous
    ensure_cache_dir # Ensure cache directory is ready before downloads
    download_files
    install_files
    setup_service
    install_shortcuts

    log "Installation complete! Find Netmaker Desktop in your applications menu."
}

# --- Run Script ---
main
