#!/bin/sh

set -eu
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
NC="\033[0m"

prepare_hp_utils() {
  puavo-pkg install /usr/share/puavo-pkg/packages/hp-bios-utils.tar.gz
  export PATH="/opt/hp/hp-flash:${PATH}"
  hp_utils_dir='/opt/hp/hp-flash'
}

use_hp_utils() {
  prepare_hp_utils

  cat << EOF
> Running Bash for you, the current working directory is "${hp_utils_dir}".
> It has "hp-flash" and "hp-repsetup".
> PATH is $PATH
> Exit Bash when done.
EOF
  (cd "$hp_utils_dir" && bash)
}

check_hash() {
  providedhash="$(xmllint --xpath "string(/BIOS/Rel[starts-with(@Bin,\"$hp_select_bios\")]/@Sha384)" "$mainboard_sysid.xml")"
  calculatedhash=$(sha384sum "$hp_select_bios" | awk '{print $1}')

  if [ -n "$providedhash" ]; then
    printf "Cryptographic hash for the binary was found in the list. Comparing it now.\n"
    if [ "$(printf "%s" "$calculatedhash" | grep -iP "^${providedhash}$")" ] ; then
      printf "${GREEN}The hash is a match, continuing.${NC}\n"
    else
      printf "${RED}The hash does NOT match, aborting.${NC}\n"
      printf "Calculated hash: %s\nProvided hash: %s\n" "$calculatedhash" "$providedhash"
      return 1
    fi
  else
    printf "${YELLOW}WARNING: No cryptographic hash found for the binary. Proceed with caution.${NC}\n"
  fi
}

flash_fwupd() {
  if ! [ -d /sys/firmware/efi ]; then
    printf "${RED}Selected option cannot be run on Legacy MBR installations! Exiting.${NC}\n"
    return 1
  fi

  # Temporarily (read-only) mount EFI partition in order to check free space
  efimount=$(mktemp -d /tmp/efimount.XXXXXX)
  efipart="$(blkid -t 'PARTLABEL="EFI system partition"' | cut -d ':' -f 1)"
  mount -r "$efipart" "$efimount"
  if [ $(lsblk --output FSAVAIL -nlb $efipart) -lt 157286400 ]; then
    printf "${RED}EFI partition has less than 150 MiB of free space, exiting.${NC}\n"
    umount "$efimount"
    return 1
  fi
  umount "$efimount"

  param=""
  version=""
  mainboard_sysid=$(dmidecode -s baseboard-product-name)
  hp_ftp_url="https://ftp.ext.hp.com/pub/pcbios"

  (wget "$hp_ftp_url/$mainboard_sysid/$mainboard_sysid.xml" -O "$mainboard_sysid.xml" && \
    if [ $# -le 2 ]; then
      for i in "${@}"; do
        if [ "$i" = "-y" ]; then
          param="$i"
        elif [ "$i" = "latest" ]; then
          version="$(xmllint --xpath "string(/BIOS/Rel/@Bin)" "$mainboard_sysid.xml")"
        elif [ "$i" != "-y" -a "$i" != "latest" ]; then
          echo "Invalid parameters!"
          echo "Accepted parameters are: '-y' and 'latest'"
          return 1
        fi
      done
    fi

    hp_select_bios="$(xmllint --xpath "(/BIOS/Rel/@Bin)" "$mainboard_sysid.xml" | cut -d '"' -f 2 \
     | fzf --query "$version" --select-1 --height=9 --layout=reverse-list --color=bg+:#FFFFFF,fg+:#000000
    )" && wget "$hp_ftp_url/$mainboard_sysid/$hp_select_bios" -O "$hp_select_bios" && \
    check_hash && fwupdtool install-blob "$hp_select_bios" $param)
}


flash() {
  prepare_hp_utils

  param=""
  version=""
  mainboard_sysid=$(dmidecode -s baseboard-product-name)
  hp_ftp_url="https://ftp.ext.hp.com/pub/pcbios"

  (cd "$hp_utils_dir" && \
    wget "$hp_ftp_url/$mainboard_sysid/$mainboard_sysid.xml" -O "$mainboard_sysid.xml" && \
    if [ $# -le 2 ]; then
      for i in "${@}"; do
        if [ "$i" = "-y" ]; then
          param="$i"
        elif [ "$i" = "latest" ]; then
          version="$(xmllint --xpath "string(/BIOS/Rel/@Bin)" "$mainboard_sysid.xml")"
        elif [ "$i" != "-y" -a "$i" != "latest" ]; then
          echo "Invalid parameters!"
          echo "Accepted parameters are: '-y' and 'latest'"
          return 1
        fi
      done
    fi

    hp_select_bios="$(xmllint --xpath "(/BIOS/Rel/@Bin)" "$mainboard_sysid.xml" | cut -d '"' -f 2 \
     | fzf --query "$version" --select-1 --height=9 --layout=reverse-list --color=bg+:#FFFFFF,fg+:#000000
    )" && wget "$hp_ftp_url/$mainboard_sysid/$hp_select_bios" -O "$hp_select_bios" && \
    check_hash && hp-flash "$hp_select_bios" $param)
}

import_config() {
  prepare_hp_utils

  config="$1"
  baseurl_git="https://raw.githubusercontent.com/opinsys/opinsys-host-configurations/main/HP"

  ### Create log file solely for gathering errors from curl.
  ### If it already exists, just move it out of the way so we can read it if needed.
  errlogfile="/tmp/puavo-bios-config-curl.log"

  if [ -f "$errlogfile" ]; then
    mv "$errlogfile" "/tmp/puavo-bios-config-curl.log.old"
  fi

  (cd "$hp_utils_dir" && curl -O --silent --show-error \
   --url "$baseurl_git/$config" \
   --write-out "$config") 2>> "$errlogfile" || true

  if [ ! -f "$hp_utils_dir/$config" ] && [ "$(grep -c . "$errlogfile")" -gt 0 ]; then
    echo "Could not find config $config in $hp_utils_dir. Config was not imported!!"
    echo "Error log has entries, see $errlogfile."
  else
    (cd "$hp_utils_dir" && hp-repsetup -s "$config")
    echo "\nSelected config $config should now be set.\nPlease check the output above to be sure.\n\n"
  fi

  echo "Returning to puavo-bios-config menu.\n"
}

ask_choice() {
  choices=$(cat <<'EOF'
Flash latest HP BIOS version (hp-flash)
Flash select HP BIOS version (hp-flash)
Flash latest HP BIOS version (fwupd)
Flash select HP BIOS version (fwupd)
Import Student laptop BIOS Config
Import Student laptop BIOS Config (UEFI)
Import USB Stick factory BIOS Config
Import USB Stick factory BIOS Config (UEFI)
use HP BIOS utilities
exit
EOF
)
  printf "%s" "$choices" | fzf --height=12 --layout=reverse-list --color=bg+:#FFFFFF,fg+:#000000
}

printf "\n"
printf ">>> Welcome to puavo-bios-config!\n"
printf ">>> What do you want to do?\n\n"

if [ $# -ge 1 ] && [ $# -le 3 ]; then
  chosen="$1"
  option2="${2:-}"
  option3="${3:-}"
  eval $chosen $option2 $option3
else
  while chosen=$(ask_choice); do
    printf ">> You chose '${chosen}'\n"

    case "$chosen" in
      exit)
        exit 0
        ;;
      'Flash latest HP BIOS version (hp-flash)')
        flash latest
        sleep 3
        ;;
      'Flash select HP BIOS version (hp-flash)')
        flash
        sleep 3
        ;;
      'Flash latest HP BIOS version (fwupd)')
        flash_fwupd latest
        sleep 3
        ;;
      'Flash select HP BIOS version (fwupd)')
        flash_fwupd
        sleep 3
        ;;
      'Import Student laptop BIOS Config')
        import_config HpSetup-student-laptop.txt
        sleep 3
        ;;
      'Import Student laptop BIOS Config (UEFI)')
        import_config HpSetup-student-laptop-uefi.txt
        sleep 3
        ;;
      'Import USB Stick factory BIOS Config')
        import_config HpSetup-usb-factory.txt
        sleep 3
        ;;
      'Import USB Stick factory BIOS Config (UEFI)')
        import_config HpSetup-usb-factory-uefi.txt
        sleep 3
        ;;
      'use HP BIOS utilities')
        use_hp_utils
        ;;
    esac
  done
fi
