#!/usr/bin/env bash

# Check for available internet connection before proceeding (network-online.target doesn't work for some network connections)
# Check it 3 times in 2 second interval, to avoid until loop
# Used when adding remotes & when installing flatpaks
check_internet_connection() {
    local max_attempts=3
    local sleep_time=2
    local attempt=1

    while (( attempt <= max_attempts )); do
        if curl --silent --head --fail "https://fedoraproject.org/static/hotspot.txt" > /dev/null; then
          return 0
        else
          echo "Internet connection is not available. Waiting..."
          sleep ${sleep_time}
          (( attempt++ ))
        fi
    done

    return 1
}

REPO_INFO="/usr/share/bluebuild/default-flatpaks/system/repo-info.json"
REPO_URL=$(jq -r 'try .["repo-url"]' $REPO_INFO)
REPO_NAME=$(jq -r 'try .["repo-name"]' $REPO_INFO)
REPO_TITLE=$(jq -r 'try .["repo-title"]' $REPO_INFO)

# Opt out of and remove Fedora's system flatpak repos
FLATPAK_SYSTEM_REMOTES=($(flatpak --system remotes))

fedora_system=false
fedora_testing_system=false

for system_remote in "${FLATPAK_SYSTEM_REMOTES[@]}"; do
  if [[ "${system_remote}" == "fedora" ]]; then
    fedora_system=true
  elif [[ "${system_remote}" == "fedora-testing" ]]; then
    fedora_testing_system=true
  fi
done

if rpm -q fedora-third-party &>/dev/null; then
  if [[ ! "$(fedora-third-party query)" == *"disabled." ]]; then
    echo "Disabling Fedora third-party repos..."
    if command -v gnome-software &> /dev/null; then
      if ps aux | grep -v grep | grep -E -q " /sbin/gnome-software | /bin/gnome-software | /usr/sbin/gnome-software | /usr/bin/gnome-software | gnome-software "; then
        /usr/bin/gnome-software --quit
      fi
    fi
    /usr/lib/fedora-third-party/fedora-third-party-opt-out
    /usr/bin/fedora-third-party disable
  else
     echo "Fedora third-party repos are already disabled"
  fi
else
  echo "There is no need to opt-out from Fedora 3rd party repos, because 'fedora-third-party' package is already removed."
fi

# Remove fedora system remote, unless fedora remote is strictly specified
if [[ ! "${REPO_URL}" == "oci+https://registry.fedoraproject.org" ]]; then
  if "${fedora_system}"; then
    echo "Removing system flatpak remote 'fedora'"
    flatpak remote-delete --system fedora --force
  else
    echo "System flatpak remote 'fedora' is already removed"  
  fi
else
  echo "Not removing the system flatpak remote 'fedora', as it's specified for use in config"  
fi

if "${fedora_testing_system}"; then
  echo "Removing system flatpak remote 'fedora-testing'"
  flatpak remote-delete --system fedora-testing --force
else
  echo "System flatpak remote 'fedora-testing' is already removed"  
fi

# Remove flatpak apps from system origin fedora, unless fedora remote is strictly specified
if [[ ! "${REPO_URL}" == "oci+https://registry.fedoraproject.org" ]]; then
  FEDORA_FLATPAKS_APP=($(flatpak list --system --app --columns=application,origin | awk '$2 == "fedora" {print $1}'))
  if [[ ${#FEDORA_FLATPAKS_APP[@]} -gt 0 ]]; then
    echo "Removing system flatpak apps from 'fedora' remote"
    flatpak remove --system --noninteractive "${FEDORA_FLATPAKS_APP[@]}"
  else
    echo "System flatpak apps from 'fedora' remote are already removed"
  fi
else
  echo "Not automatically removing all flatpak apps from system remote 'fedora', as it's specified for use in config"
fi

# Remove flatpak runtimes from system origin fedora, unless fedora remote is strictly specified
if [[ ! "${REPO_URL}" == "oci+https://registry.fedoraproject.org" ]]; then
  FEDORA_FLATPAKS_RUNTIME=($(flatpak list --system --runtime --columns=application,arch,branch,origin | awk '$4 == "fedora" {print $1"/"$2"/"$3}'))
  if [[ ${#FEDORA_FLATPAKS_RUNTIME[@]} -gt 0 ]]; then
    echo "Removing system flatpak runtimes from 'fedora' remote"
    flatpak remove --system --noninteractive "${FEDORA_FLATPAKS_RUNTIME[@]}"
  else
    echo "System flatpak runtimes from 'fedora' remote are already removed"
  fi  
else
  echo "Not automatically removing all flatpak runtimes from system remote 'fedora', as it's specified for use in config"
fi

# Remove flatpak apps from system origin fedora-testing
FEDORA_TESTING_FLATPAKS_APP=($(flatpak list --system --app --columns=application,origin | awk '$2 == "fedora-testing" {print $1}'))
if [[ ${#FEDORA_TESTING_FLATPAKS_APP[@]} -gt 0 ]]; then
  echo "Removing system flatpak apps from 'fedora-testing' remote"
  flatpak remove --system --noninteractive "${FEDORA_TESTING_FLATPAKS_APP[@]}"
else
  echo "System flatpak apps from 'fedora-testing' remote are already removed"
fi  

# Remove flatpak runtimes from system origin fedora-testing
FEDORA_TESTING_FLATPAKS_RUNTIME=($(flatpak list --system --runtime --columns=application,arch,branch,origin | awk '$4 == "fedora-testing" {print $1"/"$2"/"$3}'))
if [[ ${#FEDORA_TESTING_FLATPAKS_RUNTIME[@]} -gt 0 ]]; then
  echo "Removing system flatpak runtimes from 'fedora-testing' remote"
  flatpak remove --system --noninteractive "${FEDORA_TESTING_FLATPAKS_RUNTIME[@]}"
else
  echo "System flatpak runtimes from 'fedora-testing' remote are already removed"
fi  

# General conditions for not running the unnecessary flatpak setup
# Currently, we don't modify remote title if it's already modified
# Flatpak add remote is ran for some reason, even with --if-not-exists flag, apparently, it modifies the URL
# We cannot compare repo URLs properly
# Flatpak outputs repo URL, while we have flatpakref URL, which is not the same
no_title_modify=false
readarray -t CURRENT_REPO_INFO < <(flatpak remotes --system --columns=name,url,title)
for index in "${CURRENT_REPO_INFO[@]}"; do
    CURRENT_REPO_NAMES+=("$(echo "${index}" | awk '{print $1}')")
    CURRENT_REPO_TITLES+=("$(echo "${index}" | awk '{ for(i=3;i<NF;i++) printf "%s ", $i; print $NF }')")
    for name in "${CURRENT_REPO_NAMES[@]}"; do
      for title in "${CURRENT_REPO_TITLES[@]}"; do
      if [[ "${name}" == "${REPO_NAME}" ]] && [[ "${title}" == "${REPO_TITLE}" ]]; then
        no_title_modify=true
      fi
      done  
    done
done

# Set up system-wide Flatpak repository
if [[ $REPO_URL != "null" && $REPO_NAME != "null" ]]; then
  if check_internet_connection; then
    echo "Adding system-wide remote $REPO_NAME from $REPO_URL if it doesn't exist (requires internet)"  
    flatpak remote-add --if-not-exists --system "$REPO_NAME" "$REPO_URL"
  else
    echo "NOTE: Skipping the addition of system-wide remote, because there is no internet connection"  
  fi  
fi

# If configured remote is flathub, enable it here.
# Flathub is already installed in Fedora, but not enabled by default,
# so the above command won't add it again
if [[ $REPO_NAME == "flathub" ]]; then
  echo "Enabling specified 'flathub' remote, that is already installed, but disabled in Fedora"
  flatpak remote-modify --system "$REPO_NAME" --enable
fi

# Change repository title to configured title, if not null & if not already changed
if [[ $REPO_TITLE != "null" ]] && ! ${no_title_modify}; then
  echo "Setting title $REPO_TITLE for system remote $REPO_NAME"
  flatpak remote-modify --system "$REPO_NAME" --title="$REPO_TITLE"
elif [[ $REPO_TITLE != "null" ]] && ${no_title_modify}; then
  echo "Custom flatpak system remote title is already set"  
fi

# Notifications config
NOTIFICATIONS_FILE="/usr/share/bluebuild/default-flatpaks/notifications"
USER_NOTIFICATIONS_FILE="/etc/bluebuild/default-flatpaks/notifications"
# Ignore words starting with # symbol, whitelines & duplicate entries for notifications config
MAINTAINER_NOTIFICATIONS=$(cat "$NOTIFICATIONS_FILE" | grep -v -E '^#|^$' | awk '!seen[$0]++')
USER_NOTIFICATIONS=$(cat "$USER_NOTIFICATIONS_FILE" | grep -v -E '^#|^$' | awk '!seen[$0]++')

# If user modified notifications config, utilize user's configuration, otherwise maintainer's
if [[ -n $USER_NOTIFICATIONS ]]; then
  NOTIFICATIONS="$USER_NOTIFICATIONS"
else
  NOTIFICATIONS="$MAINTAINER_NOTIFICATIONS"
fi  

# Installed flatpaks
FLATPAK_LIST=$(flatpak list --system --app --columns=application)

# Flatpak list files
INSTALL_LIST_FILE="/usr/share/bluebuild/default-flatpaks/system/install"
REMOVE_LIST_FILE="/usr/share/bluebuild/default-flatpaks/system/remove"
USER_INSTALL_LIST_FILE="/etc/bluebuild/default-flatpaks/system/install"
USER_REMOVE_LIST_FILE="/etc/bluebuild/default-flatpaks/system/remove"
# Prefer user's install + remove list over maintainer's, in case when same flatpak ID is present in maintainer's install list + user's remove list & vice-versa
# Also ignores words starting with # symbol, whitelines & duplicate entries
MAINTAINER_INSTALL_LIST=$(comm -23 <(sort "$INSTALL_LIST_FILE") <(sort "$USER_REMOVE_LIST_FILE") | grep -v -E '^#|^$' | awk '!seen[$0]++')
MAINTAINER_REMOVE_LIST=$(comm -23 <(sort "$REMOVE_LIST_FILE") <(sort "$USER_INSTALL_LIST_FILE") | grep -v -E '^#|^$' | awk '!seen[$0]++')
# Combine maintainer & user list. Ignore words starting with # symbol, whitelines & duplicate entries
COMBINED_INSTALL_LIST=$(cat <(echo "$MAINTAINER_INSTALL_LIST") "$USER_INSTALL_LIST_FILE" | grep -v -E '^#|^$' | awk '!seen[$0]++')
COMBINED_REMOVE_LIST=$(cat <(echo "$MAINTAINER_REMOVE_LIST") "$USER_REMOVE_LIST_FILE" | grep -v -E '^#|^$' | awk '!seen[$0]++')

# Loginctl has different command for parsing json since v256 (F41), so handle that scenario here
LOGINCTL_VERSION=$(loginctl --version | awk 'NR==1 {print $2}')
function notify-send-pre-install {
     if [[ ${LOGINCTL_VERSION} -ge 256 ]]; then
       user_name=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .uid')
     else
       user_name=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .uid')
     fi
     xdg_runtime_path="/run/user/$uid"
     sudo -u "$user_name" DBUS_SESSION_BUS_ADDRESS=unix:path="$xdg_runtime_path"/bus notify-send "Flatpak Installer" "Started install of system flatpaks" --app-name="Flatpak Installer" -u NORMAL
}

function notify-send-install {
     if [[ ${LOGINCTL_VERSION} -ge 256 ]]; then
       user_name=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .uid')
     else
       user_name=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .uid')
     fi
     xdg_runtime_path="/run/user/$uid"
     sudo -u "$user_name" DBUS_SESSION_BUS_ADDRESS=unix:path="$xdg_runtime_path"/bus notify-send "Flatpak Installer" "Finished install of system flatpaks:\n$INSTALL_LIST" --app-name="Flatpak Installer" -u NORMAL
}

function notify-send-pre-uninstall {
     if [[ ${LOGINCTL_VERSION} -ge 256 ]]; then
       user_name=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .uid')
     else
       user_name=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .uid')
     fi
     xdg_runtime_path="/run/user/$uid"
     sudo -u "$user_name" DBUS_SESSION_BUS_ADDRESS=unix:path="$xdg_runtime_path"/bus notify-send "Flatpak Installer" "Started uninstall of some system flatpaks" --app-name="Flatpak Installer" -u NORMAL
}

function notify-send-uninstall {
     if [[ ${LOGINCTL_VERSION} -ge 256 ]]; then
       user_name=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users -j | jq -r '.[] | select(.state == "active") | .uid')
     else
       user_name=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .user')
       uid=$(loginctl list-users --output=json | jq -r '.[] | select(.state == "active") | .uid')
     fi
     xdg_runtime_path="/run/user/$uid"
     sudo -u "$user_name" DBUS_SESSION_BUS_ADDRESS=unix:path="$xdg_runtime_path"/bus notify-send "Flatpak Installer" "Finished uninstall of system flatpaks:\n$REMOVE_LIST" --app-name="Flatpak Installer" -u NORMAL
}

# Remove flatpaks in list
if [[ -f $REMOVE_LIST_FILE ]] || [[ -f $USER_REMOVE_LIST_FILE ]]; then
  REMOVE_LIST=$(comm -12 <(echo "$COMBINED_REMOVE_LIST" | sort) <(echo "$FLATPAK_LIST" | sort))
  if [[ -n $REMOVE_LIST ]] && [[ ! $NOTIFICATIONS == "true" ]]; then
    echo "Removing system flatpaks from config list"
    flatpak uninstall --system --noninteractive ${REMOVE_LIST[@]}
  elif [[ -n $REMOVE_LIST ]] && [[ $NOTIFICATIONS == "true" ]]; then
    echo "Removing system flatpaks from config list"
    notify-send-pre-uninstall
    flatpak uninstall --system --noninteractive ${REMOVE_LIST[@]}
    notify-send-uninstall
  fi
fi

# Install flatpaks in list
if [[ -f $INSTALL_LIST_FILE ]] || [[ -f $USER_INSTALL_LIST_FILE ]]; then
  if [[ -n $FLATPAK_LIST ]]; then
    INSTALL_LIST=$(comm -23 <(echo "$COMBINED_INSTALL_LIST" | sort) <(echo "$FLATPAK_LIST" | sort))
  else
    INSTALL_LIST="$COMBINED_INSTALL_LIST"
  fi
  if [[ -n $INSTALL_LIST ]] && [[ ! $NOTIFICATIONS == "true" ]]; then
    if check_internet_connection; then
      echo "Installing system flatpaks from config list (requires internet)"
      flatpak install --system --noninteractive "$REPO_NAME" ${INSTALL_LIST[@]}
    else
      echo "ERROR: Installation of system flatpaks was not performed, because there was no internet connection"
      exit 1   
    fi  
  elif  [[ -n $INSTALL_LIST ]] && [[ $NOTIFICATIONS == "true" ]]; then
    if check_internet_connection; then
      echo "Installing system flatpaks from config list (requires internet)"
      notify-send-pre-install
      flatpak install --system --noninteractive "$REPO_NAME" ${INSTALL_LIST[@]}
      notify-send-install
    else
      echo "ERROR: Installation of system flatpaks was not performed, because there was no internet connection"
      exit 1  
    fi  
  fi
fi
