#!/bin/bash
# ============================================================
# TimeChamp Tracker — unified Linux installer.
#
# One installer for both build variants:
#   * interactive ("timechamp") — normal tracker with UI/tray icon
#   * silent      ("svcvtt")    — inconspicuous build, different
#                                 on-disk name and paths
#
# The release ships this script inside a folder downloaded from the
# site, named "TimeChamp" for the interactive build or "Svcvtt" for
# the silent build. The variant is detected from that containing
# folder name — no build-time token replacement needed. If the
# folder name matches neither (e.g. the script is run straight from
# source), it defaults to the interactive variant.
#
# Everything else — install path, download URL, tray icon, the
# cron watchdog (pickup-service) — is derived from that one value.
# ============================================================

SELF_DIR=$(cd "$(dirname "$(readlink -f "$0")")" 2>/dev/null && pwd)
case "$SELF_DIR" in
    */[Ss]vcvtt) TC_VARIANT="silent";      APPDIR="svcvtt";    DLDIR="Silent"      ;;
    *)           TC_VARIANT="interactive"; APPDIR="timechamp"; DLDIR="Interactive" ;;
esac
SHARE="$HOME/.local/share/$APPDIR"

echo "TimeChamp installer — variant: ${TC_VARIANT} (dir: $APPDIR), detected from: $SELF_DIR"

# ---------- remove previous installs / leftovers ----------
killall -9 time-champ.-tracker.-electron 2>/dev/null
killall -9 TimeChamp.Tracker.Electron 2>/dev/null
killall -9 TimeChamp.AppImage 2>/dev/null
killall -9 "time-champ.-tracker.-electron --no-sandbox" 2>/dev/null
rm -rf "$SHARE"
rm -rf ~/TimeChampDevDebug ~/TimeChamp ~/Svcvtt
rm -rf ~/.cache/tracker ~/.local/share/tracker ~/.cache/tracker3 ~/.local/share/tracker3
find ~/.cache -type d -name 'tracker*' -prune -exec rm -rf {} + 2>/dev/null
find ~/.local/share -type d -name 'tracker*' -prune -exec rm -rf {} + 2>/dev/null
rm -rf ~/.config/time-champ.-tracker.-electron

# Drop any stale cron entries from previous installs — both the old
# per-variant service names and the unified one.
for pat in 'timechamp-service' 'svcvtt-service' 'pickup-service'; do
    crontab -u "$USER" -l 2>/dev/null | grep -v "$pat" | crontab -u "$USER" - 2>/dev/null
done

# ---------- download the AppImage for this variant ----------
{
wget "https://tracker.app.timechamp.io/Tracker/Linux/5.8.1.98/$DLDIR/TimeChamp.AppImage"
} ||
{
wget "https://tracker.app.timechamp.io/Tracker/Linux/5.8.1.98/$DLDIR/TimeChamp.AppImage" --no-check-certificate
}

appImagePath=$(date --utc +'%Y%m%d%H%M%S')

mkdir -p "$SHARE/$appImagePath"
mv TimeChamp.AppImage "$SHARE/$appImagePath/"
chmod -R 777 "$SHARE/$appImagePath/TimeChamp.AppImage"
"$SHARE/$appImagePath/TimeChamp.AppImage" --appimage-extract
mv squashfs-root "$SHARE/$appImagePath/executables"

# ScriptFiles is published alongside the app binary, so inside the
# extracted AppImage it lives under usr/bin — NOT at the AppDir root.
SCRIPTS_DIR="$SHARE/$appImagePath/executables/usr/bin/ScriptFiles"

# ---------- tray icon (interactive build only) ----------
if [ "$TC_VARIANT" != "silent" ]; then
    {
    wget https://customer.sites2.timechamp.io/tracker/linux/timechamp_logo.png
    } ||
    {
    wget https://customer.sites2.timechamp.io/tracker/linux/timechamp_logo.png --no-check-certificate
    }
    mv timechamp_logo.png "$SHARE/" 2>/dev/null || true
fi

# ---------- desktop entry (interactive build only) ----------
# Write the .desktop launcher NOW, at install time, so the desktop
# environment has it cached *before* the tracker's window first maps.
# The app also writes this at runtime (UnityConfig), but on a fresh
# install that happens too late for the first launch — GNOME matches
# the window to no .desktop and shows a generic gear icon until its
# app cache catches up (~1 min). Creating it here, ahead of first
# launch, makes the app logo appear immediately. StartupWMClass must
# equal the window's WM_CLASS ("TimeChamp").
if [ "$TC_VARIANT" != "silent" ]; then
    APPS_DIR="$HOME/.local/share/applications"
    mkdir -p "$APPS_DIR"
    cat > "$APPS_DIR/timechamp.desktop" <<EOF
[Desktop Entry]
Name=TimeChamp
Comment=Time & Productivty Application
Exec=$SHARE/$appImagePath/executables/AppRun
Terminal=false
Type=Application
Icon=$SHARE/timechamp_logo.png
StartupWMClass=TimeChamp
Keywords=time;Time;
EOF
    update-desktop-database "$APPS_DIR" 2>/dev/null || true
fi

# ============================================================
# Privileged input-access setup (keystroke + mouse capture).
#
# Delegates to the canonical setup-input-access.sh shipped inside
# the AppImage. That script installs the udev `uaccess` rule for
# /dev/input/event*, /dev/hidraw* and /dev/uinput, adds the user to
# the 'input' group, applies setfacl to the live device nodes, and
# installs libXtst. It writes to /etc/udev/rules.d and runs setfacl,
# so it needs root — we invoke it with `sudo` (one password prompt),
# the same way uninstall.bash escalates its privileged step. The
# script itself resolves the real user from SUDO_USER, so it still
# configures access for the invoking user, not root. Doing this at
# install time means keystroke capture works on first launch with NO
# pkexec prompt; the script is still re-run via pkexec on first
# launch as a self-heal fallback if this is skipped.
# ============================================================
INPUT_ACCESS_SCRIPT="$SCRIPTS_DIR/setup-input-access.sh"
if [ ! -f "$INPUT_ACCESS_SCRIPT" ]; then
    INPUT_ACCESS_SCRIPT=$(ls -t "$SHARE"/*/executables/usr/bin/ScriptFiles/setup-input-access.sh 2>/dev/null | head -1)
fi
if [ -n "$INPUT_ACCESS_SCRIPT" ] && [ -f "$INPUT_ACCESS_SCRIPT" ]; then
    chmod +x "$INPUT_ACCESS_SCRIPT" 2>/dev/null || true
    echo "Running input-access setup (will ask for your password): $INPUT_ACCESS_SCRIPT"
    sudo bash "$INPUT_ACCESS_SCRIPT" || \
        echo "WARNING: input-access setup exited non-zero; tracker will prompt once via pkexec on first launch instead"
else
    echo "WARNING: setup-input-access.sh not found in extracted AppImage."
fi

# ============================================================
# Privileged screen-capture helper.
#
# Delegates to the canonical setup-capture-helper.sh that ships inside
# the AppImage — ffmpeg + libcap utils + GPU VAAPI driver across every
# supported distro, and setcap cap_sys_admin,cap_dac_override on the
# kmsgrab helper. setcap and the package install need root, so this is
# invoked with `sudo` too (the credential from the input-access step
# above is normally still cached, so no second password prompt). The
# script resolves the real user from SUDO_USER and builds the helper
# into that user's home. Re-run via pkexec on first launch if skipped.
# ============================================================
CAPTURE_HELPER_SCRIPT="$SCRIPTS_DIR/setup-capture-helper.sh"
if [ ! -f "$CAPTURE_HELPER_SCRIPT" ]; then
    CAPTURE_HELPER_SCRIPT=$(ls -t "$SHARE"/*/executables/usr/bin/ScriptFiles/setup-capture-helper.sh 2>/dev/null | head -1)
fi
if [ -n "$CAPTURE_HELPER_SCRIPT" ] && [ -f "$CAPTURE_HELPER_SCRIPT" ]; then
    chmod +x "$CAPTURE_HELPER_SCRIPT" 2>/dev/null || true
    echo "Running capture helper setup: $CAPTURE_HELPER_SCRIPT"
    # $SHARE/capture holds both the setcap'd loader and the auto-
    # updateable core.so (variant-scoped: svcvtt/capture for silent,
    # timechamp/capture for interactive).
    sudo bash "$CAPTURE_HELPER_SCRIPT" "$SHARE/capture" || \
        echo "WARNING: capture helper setup exited non-zero; tracker will use Mutter ScreenCast fallback (indicator visible)"
else
    echo "WARNING: setup-capture-helper.sh not found in extracted AppImage."
fi

# ============================================================
# Install the cron watchdog.
#
# pickup-service is the unified watchdog (it auto-detects its
# variant from its own install directory). We copy the canonical
# copy out of the extracted AppImage instead of embedding one
# inline — the tracker later refreshes it from the server via
# Program.cs.UpdateTheLatestAOSServiceScript().
# ============================================================
if [ -f "$SCRIPTS_DIR/pickup-service" ]; then
    cp "$SCRIPTS_DIR/pickup-service" "$SHARE/pickup-service"
    chmod 777 "$SHARE/pickup-service"
    echo "Installed watchdog: $SHARE/pickup-service"
else
    echo "WARNING: pickup-service not found in extracted AppImage."
fi

# ============================================================
# Install wmctrl (window raiser).
#
# The tracker uses wmctrl to bring its window to the front on idle
# without the desktop's focus-stealing notification. Install it NOW,
# at install time, into $SHARE so it's present from the tracker's very
# first launch — this clean-install step wiped $SHARE, and the
# pickup-service watchdog only re-downloads wmctrl about a minute
# later, leaving a gap where idle prompts would fall back to a
# notification. Best-effort: the watchdog still re-installs it as a
# self-heal if this fails. No sudo — wmctrl is unpacked into $SHARE.
# ============================================================
if [ "$TC_VARIANT" != "silent" ] && [ ! -x "$SHARE/wmctrl" ]; then
    echo "Installing wmctrl..."
    WM_TMP=$(mktemp -d)
    (
        set +e
        cd "$WM_TMP" || exit 0
        if command -v apt-get >/dev/null 2>&1; then
            apt-get download wmctrl && dpkg-deb -x ./*.deb . && mv ./usr/bin/wmctrl "$SHARE/wmctrl"
        elif command -v dnf >/dev/null 2>&1; then
            # RHEL family (AlmaLinux/Rocky/RHEL/CentOS) keeps wmctrl in EPEL, and
            # `dnf download` needs the download plugin. Enable both first (harmless
            # on Fedora, where wmctrl is already in the base repos). The sudo
            # credential from the input-access step above is normally still cached.
            sudo dnf install -y dnf-plugins-core >/dev/null 2>&1 || true
            sudo dnf install -y epel-release     >/dev/null 2>&1 || true
            dnf download --enablerepo='epel*' wmctrl && rpm2cpio ./*.rpm | cpio -idm && mv ./usr/bin/wmctrl "$SHARE/wmctrl"
        elif command -v zypper >/dev/null 2>&1; then
            zypper --non-interactive download wmctrl && rpm2cpio ./*.rpm | cpio -idm && mv ./usr/bin/wmctrl "$SHARE/wmctrl"
        elif command -v pacman >/dev/null 2>&1; then
            curl -fLO "$(pacman -Sp --noconfirm wmctrl)" && bsdtar -xf ./*.pkg.tar.* usr/bin/wmctrl && mv ./usr/bin/wmctrl "$SHARE/wmctrl"
        elif command -v apk >/dev/null 2>&1; then
            apk fetch wmctrl && tar -xzf ./*.apk && mv ./usr/bin/wmctrl "$SHARE/wmctrl"
        fi
    ) || true
    rm -rf "$WM_TMP"
    if [ -f "$SHARE/wmctrl" ]; then
        chmod +x "$SHARE/wmctrl"
        echo "Installed wmctrl: $SHARE/wmctrl"
    else
        echo "WARNING: wmctrl not installed at install time; the watchdog will retry."
    fi
fi

# ---------- ensure a working cron daemon (the watchdog needs it) ----------
# The pickup-service watchdog is scheduled via cron. Arch-based distros such as
# Omarchy ship NO cron by default, so the crontab line below would silently no-op
# and the tracker would never persist/self-heal. Install cron if missing, then
# make sure its daemon is enabled + running (package/service names vary by distro).
if ! command -v crontab >/dev/null 2>&1; then
    echo "cron not found — installing..."
    if   command -v pacman  >/dev/null 2>&1; then sudo pacman -S --noconfirm --needed cronie
    elif command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y cron
    elif command -v dnf     >/dev/null 2>&1; then sudo dnf install -y cronie
    elif command -v zypper  >/dev/null 2>&1; then sudo zypper --non-interactive install cronie
    elif command -v apk     >/dev/null 2>&1; then sudo apk add cronie
    fi
fi
for _svc in cronie crond cron; do
    sudo systemctl enable --now "$_svc" 2>/dev/null && { echo "cron daemon: $_svc enabled"; break; }
done

(crontab -l 2>/dev/null; echo "*/1 * * * * $SHARE/pickup-service $SHARE/TimeChamp.AppImage time-champ.-tra 2 > $SHARE/$APPDIR.log 2>&1") | awk '!x[$0]++' | crontab -

# ---------- launch ----------
nohup "$SHARE/$appImagePath/executables/AppRun" &

# ---------- post-install notice (GNOME Wayland only) ----------
# The bundled focus-reporter GNOME Shell extension — which lets the tracker see
# native-Wayland apps (JetBrains IDEs, etc.) — is loaded by GNOME only at login.
# So on a GNOME Wayland session, ask the user to log out and back in once. On
# X11/Xorg and non-GNOME desktops nothing extra is needed, so we stay silent.
_tc_desktop="${XDG_CURRENT_DESKTOP:-}${XDG_SESSION_DESKTOP:-}${GDMSESSION:-}"
_tc_stype="${XDG_SESSION_TYPE:-}"
if { [ "$_tc_stype" = "wayland" ] || { [ -z "$_tc_stype" ] && [ -n "${WAYLAND_DISPLAY:-}" ]; }; } \
   && printf '%s' "$_tc_desktop" | grep -qi gnome; then
    echo ""
    echo "============================================================"
    echo "  IMPORTANT: please LOG OUT and LOG BACK IN once."
    echo ""
    echo "  This one-time step activates full activity tracking on"
    echo "  GNOME Wayland (native-Wayland apps such as Android Studio"
    echo "  and Rider). Everything else already works right away."
    echo "============================================================"
    echo ""
    # Also surface it as a desktop notification, if possible (non-fatal).
    command -v notify-send >/dev/null 2>&1 && \
        notify-send "TimeChamp installed" \
            "Please log out and log back in once to finish setup." 2>/dev/null || true
fi

exit
