#!/usr/bin/env bash
# epc670-update — Update epc apt packages and Python environment.
#
# Upgrades apt packages and pip packages listed in /etc/epc670/monitored-packages.conf.
# Intended to be run from the desktop shortcut via lxterminal.
#
# Options:
#   --noprompt    Skip reboot prompt and warning dialogs after update.

set -euo pipefail

EPC_VENV="/opt/venv/epc670"
PACKAGES_CONF="/etc/epc670/monitored-packages.conf"
REBOOT_REQUIRED_FLAG="/tmp/epc-reboot-required"

# ---------------------------------------------------------------------------
# Parse arguments
# ---------------------------------------------------------------------------
NO_PROMPT=false
NO_INPUT=false
for ARG in "$@"; do
    case "$ARG" in
        --noprompt) NO_PROMPT=true ;;
        --noinput)  NO_INPUT=true  ;;
        *) echo "Warning: unknown argument '${ARG}'" >&2 ;;
    esac
done

# ---------------------------------------------------------------------------
# Parse monitored-packages.conf
# ---------------------------------------------------------------------------
APT_PACKAGES=()
APT_PACKAGES_NOT_READY=()
PYTHON_PACKAGES=()
PYTHON_PACKAGES_NOT_READY=()

if [[ ! -f "$PACKAGES_CONF" ]]; then
    echo "ERROR: packages config not found at ${PACKAGES_CONF}" >&2
    exit 1
fi

while IFS= read -r LINE; do
    # Strip comments and blank lines
    LINE="${LINE%%#*}"
    LINE="${LINE//[[:space:]]/}"
    [[ -z "$LINE" ]] && continue

    TYPE="${LINE%%:*}"
    SPEC="${LINE#*:}"

    case "$TYPE" in
        apt)
            if [[ "$SPEC" == *'?' ]]; then
                APT_PACKAGES_NOT_READY+=("${SPEC%?}")
            else
                APT_PACKAGES+=("$SPEC")
            fi
            ;;
        pip)
            if [[ "$SPEC" == *'?' ]]; then
                PYTHON_PACKAGES_NOT_READY+=("${SPEC%?}")
            else
                PYTHON_PACKAGES+=("$SPEC")
            fi
            ;;
        *)
            echo "  Warning: unknown package type '${TYPE}' in ${PACKAGES_CONF}, skipping." >&2
            ;;
    esac
done < "$PACKAGES_CONF"


# ── Helper: print a table from an array of "Name|Version|Status" rows ──────
print_table() {
    local TITLE="$1"
    shift
    local ROWS=("$@")

    local COL1=4 COL2=7
    for ROW in "${ROWS[@]}"; do
        IFS='|' read -r NAME VER _ <<< "$ROW"
        [[ ${#NAME} -gt $COL1 ]] && COL1=${#NAME}
        [[ ${#VER}  -gt $COL2 ]] && COL2=${#VER}
    done

    local BORDER
    BORDER=$(printf '+-%*s-+-%*s-+' "-$COL1" "" "-$COL2" "" | tr ' ' '-')

    echo ""
    echo "  $TITLE"
    echo "$BORDER"
    printf '| %-*s | %-*s |\n' "$COL1" "Name" "$COL2" "Version"
    echo "$BORDER"
    for ROW in "${ROWS[@]}"; do
        IFS='|' read -r NAME VER STATUS <<< "$ROW"
        if [[ "$STATUS" == "ok" ]]; then
            printf '| %-*s | %-*s |\n' "$COL1" "$NAME" "$COL2" "$VER"
        else
            printf '| %-*s | %-*s |\n' "$COL1" "$NAME" "$COL2" "N/A  ($STATUS)"
        fi
    done
    echo "$BORDER"
}

# ── Title ────────────────────────────────────────────────────────────────────
REPORT_TITLE=" epc Update Report "
REPORT_BORDER=$(printf "%${#REPORT_TITLE}s" | tr " " "=")
echo "$REPORT_BORDER"
echo "$REPORT_TITLE"
echo "$REPORT_BORDER"

# ── Network check ────────────────────────────────────────────────────────────
echo ""
echo "Checking network connection..."

CHECK_HOSTS=(
    "https://pypi.org"
    "https://google.com"
    "https://cloudflare.com"
    "https://1.1.1.1"
)
NETWORK_OK=false
for HOST in "${CHECK_HOSTS[@]}"; do
    if curl -s --max-time 3 --head "$HOST" &>/dev/null; then
        NETWORK_OK=true
        break
    fi
done

if [[ "$NETWORK_OK" == false ]]; then
    echo ""
    echo "ERROR: No network connection. All curl attempts failed."
    echo "       Please check your network and try again."
    echo ""
    [[ "$NO_INPUT" == false ]] && read -rp "Press Enter to close"
    exit 1
fi
echo "Network OK."

# ── APT packages ─────────────────────────────────────────────────────────────
echo ""
echo "[1/2] Updating apt packages..."
sudo apt update -q

APT_ROWS=()
for PKG in "${APT_PACKAGES[@]}"; do
    VERSION_BEFORE=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || true)
    sudo apt install -y "$PKG"
    VERSION_AFTER=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || true)

    if [[ -z "$VERSION_AFTER" ]]; then
        APT_ROWS+=("$PKG|—|not installed")
    elif [[ -n "$VERSION_BEFORE" && "$VERSION_BEFORE" != "$VERSION_AFTER" ]]; then
        APT_ROWS+=("$PKG|$VERSION_AFTER|ok")
    fi
done

# Optional apt packages — attempt install but treat unavailability as non-fatal.
for PKG in "${APT_PACKAGES_NOT_READY[@]}"; do
    VERSION_BEFORE=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || true)
    APT_INSTALL_OK=true
    ( sudo apt install -y "$PKG" 2>/dev/null ) || APT_INSTALL_OK=false
    if [[ "$APT_INSTALL_OK" == true ]]; then
        VERSION_AFTER=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || true)
        if [[ -n "$VERSION_AFTER" && -n "$VERSION_BEFORE" && "$VERSION_BEFORE" != "$VERSION_AFTER" ]]; then
            APT_ROWS+=("$PKG|$VERSION_AFTER|ok")
        fi
    else
        : # not available yet — silent
    fi
done

# ── Python packages ───────────────────────────────────────────────────────────
echo ""
echo "[2/2] Updating Python packages in ${EPC_VENV}..."

PYTHON_ROWS=()
if [[ ! -x "${EPC_VENV}/bin/pip" ]]; then
    for PKG in "${PYTHON_PACKAGES[@]}"; do
        PYTHON_ROWS+=("$PKG|—|venv not found")
    done
else
    # Upgrade pip itself first
    echo "  Upgrading pip..."
    "${EPC_VENV}/bin/pip" install --upgrade pip -q

    for PKG in "${PYTHON_PACKAGES[@]}"; do
        PKG_NAME="${PKG%%[><=]*}"
        PKG_SHOW_NAME="${PKG_NAME%%\[*}"
        VERSION_BEFORE=$(${EPC_VENV}/bin/pip show "$PKG_SHOW_NAME" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' || true)
        PIP_OK=true
        ( ${EPC_VENV}/bin/pip install --upgrade "$PKG" ) || PIP_OK=false
        VERSION_AFTER=$(${EPC_VENV}/bin/pip show "$PKG_SHOW_NAME" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' || true)

        if [[ "$PIP_OK" == false ]]; then
            PYTHON_ROWS+=("$PKG_NAME|—|install failed")
        elif [[ -z "$VERSION_AFTER" ]]; then
            PYTHON_ROWS+=("$PKG_NAME|—|not installed")
        elif [[ -n "$VERSION_BEFORE" && "$VERSION_BEFORE" != "$VERSION_AFTER" ]]; then
            PYTHON_ROWS+=("$PKG_NAME|$VERSION_AFTER|ok")
        fi
    done

    for PKG in "${PYTHON_PACKAGES_NOT_READY[@]}"; do
        PKG_NAME="${PKG%%[><=]*}"
        PKG_SHOW_NAME="${PKG_NAME%%\[*}"
        VERSION_BEFORE=$(${EPC_VENV}/bin/pip show "$PKG_SHOW_NAME" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' || true)

        DRY_RUN_TMP=$(mktemp)
        ${EPC_VENV}/bin/pip install --dry-run --upgrade "$PKG" >"$DRY_RUN_TMP" 2>&1 || true
        DRY_RUN_OUT=$(cat "$DRY_RUN_TMP")
        rm -f "$DRY_RUN_TMP"

        if echo "$DRY_RUN_OUT" | grep -qiE "Could not find|No matching|not find a version|No versions found"; then
            : # not available yet — silent
        else
            PIP_OK=true
            ${EPC_VENV}/bin/pip install --upgrade "$PKG" || PIP_OK=false
            if [[ "$PIP_OK" == true ]]; then
                VERSION_AFTER=$(${EPC_VENV}/bin/pip show "$PKG_SHOW_NAME" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' || true)
                if [[ -n "$VERSION_AFTER" && "$VERSION_BEFORE" != "$VERSION_AFTER" ]]; then
                    PYTHON_ROWS+=("$PKG_NAME|$VERSION_AFTER|ok")
                fi
            else
                PYTHON_ROWS+=("$PKG_NAME|—|install failed")
            fi
        fi
    done
fi

# ── Summary ───────────────────────────────────────────────────────────────────
echo ""
if [[ ${#APT_ROWS[@]} -gt 0 ]]; then
    print_table "apt packages" "${APT_ROWS[@]}"
fi

if [[ ${#PYTHON_ROWS[@]} -gt 0 ]]; then
    print_table "Python packages (/opt/venv/epc670)" "${PYTHON_ROWS[@]}"
fi

HAS_UPDATES=false
for ROW in "${APT_ROWS[@]}" "${PYTHON_ROWS[@]}"; do
    [[ "$ROW" == *"|ok" ]] && HAS_UPDATES=true && break
done

if [[ ${#APT_ROWS[@]} -eq 0 && ${#PYTHON_ROWS[@]} -eq 0 ]]; then
    echo "  All packages are already up to date."
elif [[ "$HAS_UPDATES" == true ]]; then
    echo ""
    echo "=================================================="
    echo " Updates installed. A reboot is recommended.     "
    echo "=================================================="
    echo ""
fi

[[ "$NO_INPUT" == false ]] && read -rp "Press Enter to close"

# ── Reboot prompt ─────────────────────────────────────────────────────────────
if [[ "$HAS_UPDATES" == true && "$NO_PROMPT" == false ]]; then
    if NO_AT_BRIDGE=1 yad \
        --title="Reboot Required" \
        --image="system-restart" \
        --text="Updates were installed.\nA reboot is recommended to apply all changes.\n\nReboot now?" \
        --button="Reboot now:0" \
        --button="Later:1" \
        --on-top \
        --center \
        --sticky \
        2>/dev/null; then
        rm -f "$REBOOT_REQUIRED_FLAG"
        sudo reboot
    else
        touch "$REBOOT_REQUIRED_FLAG"
        NO_AT_BRIDGE=1 yad \
            --title="Reminder" \
            --image="dialog-warning" \
            --text="Some updates may not take effect until the next reboot!" \
            --button="OK:0" \
            --on-top \
            --center \
            --sticky \
            2>/dev/null || true
    fi
elif [[ "$HAS_UPDATES" == true && "$NO_PROMPT" == true ]]; then
    touch "$REBOOT_REQUIRED_FLAG"
fi
