#!/bin/bash

set -euo pipefail

# Helper function
usage() {
  echo "
Usage: $0 <option> [--help]

  Options:
    -h, --help                 Display this help text and exit.
    -k, --keep                 Keep the dbgsym packages installed by this script.
    -d, --delete               Delete the dbgsym packages installed by this script.

  Notes:
  If no argument is provided, the script runs the default behavior.
"
}


# Coredump analyzer script
check_coredump() {
  mkdir -p "${sipwise_dir}"
  : > "${sipwise_dir}/package-dbgsym.log"
  : > "${sipwise_dir}/package-dbgsym.err"

  dbgsym_pkgs=""
  coredump=false

  echo "Checking for coredumps..."
  cd /ngcp-data/coredumps/

  while IFS= read -r -d '' core; do
    coredump=true
    corename="$(basename "$core" .zst)"
    echo
    echo "Looking into coredump file $corename"
    process=${corename#*.}
    process=${process%%.*}
    unzstd -f "$core"

    if [[ $corename =~ perl ]]; then
      echo "Extracting ${process} coredump data..."
      gdb --batch /usr/bin/perl "${corename}" -ex "thread apply all bt full" \
      > "${sipwise_dir}/${corename}.log" 2>&1
    else
      # Find full process name in case it is truncated due to max 15 char length limit.
      process=$(basename "$(find /usr/sbin /usr/bin -maxdepth 1 -type f \
      -name "${process}*" | head -n1)")

      echo "Installing ${process} dbgsym packages, it may take a while..."
      packages=$(find-dbgsym-packages "${corename}" 2>/dev/null || true)
      dbgsym_pkgs+="${packages} "
      find-dbgsym-packages --install "${corename}" \
      >> "${sipwise_dir}/package-dbgsym.log" \
      2>> "${sipwise_dir}/package-dbgsym.err"

      # Store all package name and version of the coredump
      package="$(dpkg -S "${process}" 2>/dev/null | cut -d: -f1 | head -n1 || true)"
      version="$(dpkg-query -W -f='${Version}' "${package}" 2>/dev/null)"
      pkg_versions+=(["${package}"]="${version}")

      echo "Extracting ${process} coredump data..."
      gdb --batch "${process}" "$corename" -ex "thread apply all bt full" \
      > "${sipwise_dir}/${corename}.log" 2>&1
    fi

    rm -f "${corename}"
    echo "Extraction for ${process} completed."
  done  < <(find . -name "*.zst" -print0)

  if [[ -n ${dbgsym_pkgs} ]]; then
    echo "${dbgsym_pkgs}" >> "${sipwise_dir}/installed-packages.log"
  fi


  if [[ ${coredump} = "false"  ]]; then
    echo "No coredumps found."
    exit 0
  fi
}

# Print details about process and it's running version
details() {
  report_files=$(ls "${sipwise_dir}")
  echo
  echo "Package name and version:"
  for entry in "${!pkg_versions[@]}"; do
    echo "Process: ${entry}"
    echo "Version: ${pkg_versions[${entry}]}"
    echo
  done

  if [[ -n "${report_files}" ]]; then
    echo -e "\033[1;31mCheck your coredumps details in ${sipwise_dir}/.\033[0m"
  fi
}

# Delete dbgsym packages
delete_dbgsym_pkgs() {
  if [[ -s "${sipwise_dir}/installed-packages.log" ]]; then
    echo
    echo "Removing all dbgsym packages..."
    # shellcheck disable=2046
    apt purge -y $(cat "${sipwise_dir}/installed-packages.log") \
    >> "${sipwise_dir}/package-dbgsym.log" \
    2>> "${sipwise_dir}/package-dbgsym.err"
    rm "${sipwise_dir}/installed-packages.log"
    echo "All dbgsym packages have been removed."
    echo
  else
    echo "No dbgsym packages to delete."
  fi
}


# Main Function

user="sipwise"
userhome=$(eval echo "~$user")
sipwise_dir="${userhome}/coredump-analyzer"
declare -A pkg_versions=()

# If no argument is passed
if [[ $# -eq 0 ]]; then
  check_coredump
  delete_dbgsym_pkgs
  details
  exit 0
fi

# parse input argument
case "$1" in
  --help|-h)
    usage
    exit 0
    ;;

  --keep|-k)
    check_coredump
    details
    exit 0
    ;;

  --delete|-d)
    delete_dbgsym_pkgs
    exit 0
    ;;

  *)
    echo "Invalid argument: $1"
    usage
    exit 1
    ;;
esac

