#!/bin/bash

# Enable strict error handling
set -e

# Function to log messages with timestamps
log() {
  echo "$(date '+%F %T') - $@"
}

# Function to display usage information
usage() {
  echo "Usage: $0 [-d DEVICE] [-f FARM] [-e ENVIRONMENT]"
  echo "  -d, --device DEVICE      Specify the block device to use (e.g., sda, nvme0n1)."
  echo "  -f, --farm FARM          Specify the FARM ID."
  echo "  -e, --environment ENV    Specify the environment (dev, qa, test, prod)."
  echo "  -h, --help               Display this help message."
  exit 1
}

# Function to find a suitable block device
find_blockdev() {
  # Minimum size in bytes, e.g., 10 GiB
  MIN_SIZE=$((10 * 1024 * 1024 * 1024))

  # Search for NVMe devices first
  log "Searching for NVMe devices..."
  for DEV in /dev/nvme*n1; do
    if [ -b "$DEV" ]; then
      SIZE_BYTES=$(blockdev --getsize64 "$DEV")
      if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
        log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))"
        BLOCKDEV="${DEV##*/}"
        return 0
      else
        log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
      fi
    fi
  done

  # If no NVMe device found, search for SSD devices
  log "No suitable NVMe device found. Searching for SSD devices..."
  for DEV_PATH in /sys/block/*; do
    DEV_NAME=$(basename "$DEV_PATH")
    # Exclude unwanted devices
    case "$DEV_NAME" in
    loop* | ram* | sr* | fd* | md* | dm-*)
      continue
      ;;
    esac
    DEVICE="/dev/$DEV_NAME"
    if [ -b "$DEVICE" ] && [ -e "/sys/block/$DEV_NAME/queue/rotational" ] && [ "$(cat /sys/block/$DEV_NAME/queue/rotational)" == "0" ]; then
      SIZE_BYTES=$(blockdev --getsize64 "$DEVICE")
      if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
        log "Found SSD device: $DEVICE ($(numfmt --to=iec $SIZE_BYTES))"
        BLOCKDEV="$DEV_NAME"
        return 0
      else
        log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
      fi
    fi
  done

  log "No suitable block device found."
  return 1
}

# Function to manage UEFI boot entries
manage_boot_entries() {
  log "Managing UEFI boot entries..."

  # Check if efibootmgr is available
  if ! command -v efibootmgr &>/dev/null; then
    log "Error: 'efibootmgr' is not installed. Please install it and rerun the script."
    exit 1
  fi

  # Get the list of current boot entries
  log "Retrieving current boot entries..."
  BOOT_ENTRIES_INFO=$(efibootmgr -v | grep -E "^Boot[0-9A-F]{4}")

  # Arrays to hold boot entry numbers
  NETBOOT_ENTRIES=()
  ENTRIES_TO_DELETE=()

  # Identify netboot entries and entries to delete
  while read -r LINE; do
    ENTRY_NUM=$(echo "$LINE" | awk '{print $1}' | sed 's/Boot//;s/\*//')
    ENTRY_DESC=$(echo "$LINE" | cut -d' ' -f2-)
    ENTRY_PATH=$(echo "$LINE" | awk -F'File' '{print $2}')

    # Check if the entry is a netboot entry (e.g., contains "PXE", "Network", or "IPv4"/"IPv6")
    if echo "$ENTRY_DESC" | grep -qiE "(PXE|Network|IPV4|IPV6)"; then
      NETBOOT_ENTRIES+=("$ENTRY_NUM")
      log "Identified netboot entry: Boot$ENTRY_NUM - $ENTRY_DESC"
    else
      ENTRIES_TO_DELETE+=("$ENTRY_NUM")
      log "Marking entry for deletion: Boot$ENTRY_NUM - $ENTRY_DESC"
    fi
  done <<<"$BOOT_ENTRIES_INFO"

  # Delete non-netboot entries
  if [ ${#ENTRIES_TO_DELETE[@]} -gt 0 ]; then
    log "Deleting non-netboot boot entries..."
    for ENTRY_NUM in "${ENTRIES_TO_DELETE[@]}"; do
      efibootmgr -b "$ENTRY_NUM" -B
      log "Deleted boot entry Boot$ENTRY_NUM"
    done
  else
    log "No non-netboot entries to delete."
  fi

  # Create a new boot entry pointing to BOOTX64.EFI on the first partition
  log "Creating new boot entry for /dev/${PARTPREFIX}1..."
  # Adjust the partition number if necessary
  ESP_PART_NUM=1
  efibootmgr -c -d /dev/${BLOCKDEV} -p $ESP_PART_NUM -L "Zero-OS" -l "\\EFI\\BOOT\\BOOTX64.EFI" || {
    log "Error: Failed to create new boot entry."
    exit 1
  }

  # Retrieve the new boot entry number
  NEW_BOOT_NUM=$(efibootmgr | grep "Zero-OS" | awk '{print $1}' | sed 's/\*//;s/Boot//')
  if [ -z "$NEW_BOOT_NUM" ]; then
    log "Error: Failed to retrieve new boot entry number."
    exit 1
  fi

  # Set the new boot order: netboot entries first, followed by the new boot entry
  log "Setting new BootOrder with netboot entries first..."
  BOOT_ORDER=""
  for ENTRY_NUM in "${NETBOOT_ENTRIES[@]}"; do
    BOOT_ORDER+="$ENTRY_NUM,"
  done
  BOOT_ORDER+="$NEW_BOOT_NUM"

  efibootmgr -o "$BOOT_ORDER" || {
    log "Error: Failed to set new BootOrder."
    exit 1
  }

  log "New BootOrder set successfully: $BOOT_ORDER"
}

# Main script execution
main() {
  # Default values
  BLOCKDEV_SPECIFIED=""
  FARM="1234"
  ENVIRONMENT="prod"

  # Parse command-line arguments
  while [[ $# -gt 0 ]]; do
    case "$1" in
    -d | --device)
      shift
      if [ -z "$1" ]; then
        log "Error: '--device' requires a non-empty option argument."
        usage
      fi
      BLOCKDEV_SPECIFIED="$1"
      shift
      ;;
    -f | --farm)
      shift
      if [ -z "$1" ]; then
        log "Error: '--farm' requires a non-empty option argument."
        usage
      fi
      FARM="$1"
      shift
      ;;
    -e | --environment)
      shift
      if [ -z "$1" ]; then
        log "Error: '--environment' requires a non-empty option argument."
        usage
      fi
      ENVIRONMENT="$1"
      shift
      ;;
    -h | --help)
      usage
      ;;
    *)
      log "Error: Unknown option: $1"
      usage
      ;;
    esac
  done

  # Validate environment
  case "$ENVIRONMENT" in
  dev | qa | test | prod)
    log "Using environment: $ENVIRONMENT"
    ;;
  *)
    log "Error: Invalid environment '$ENVIRONMENT'. Valid options are 'dev', 'qa', 'test', 'prod'."
    exit 1
    ;;
  esac

  if [ -n "$BLOCKDEV_SPECIFIED" ]; then
    # Use the specified block device
    if [[ "$BLOCKDEV_SPECIFIED" != /dev/* ]]; then
      BLOCKDEV_SPECIFIED="/dev/$BLOCKDEV_SPECIFIED"
    fi
    if [ ! -b "$BLOCKDEV_SPECIFIED" ]; then
      log "Error: Specified device $BLOCKDEV_SPECIFIED does not exist or is not a block device."
      exit 1
    fi
    BLOCKDEV="${BLOCKDEV_SPECIFIED##*/}"
    log "Using specified block device: $BLOCKDEV_SPECIFIED"
  else
    # Find a suitable block device
    if ! find_blockdev; then
      log "Error: No suitable block device found."
      exit 1
    fi
    log "Selected block device: /dev/${BLOCKDEV}"
  fi

  # Confirm with the user before proceeding
  read -p "This will erase all data on /dev/${BLOCKDEV}. Are you sure you want to proceed? (yes/[no]): " CONFIRM
  if [ "$CONFIRM" != "yes" ]; then
    log "Operation cancelled by user."
    exit 0
  fi

  # Determine partition naming convention
  if [[ $BLOCKDEV =~ [0-9]$ ]]; then
    PARTPREFIX="${BLOCKDEV}p"
  else
    PARTPREFIX="${BLOCKDEV}"
  fi

  # Wipe filesystem signatures
  log "Wiping filesystem signatures on /dev/${BLOCKDEV}..."
  wipefs -a -f /dev/${BLOCKDEV} || {
    log "Failed to wipe filesystem signatures."
    exit 1
  }

  # Create GPT partition table
  log "Creating GPT partition table on /dev/${BLOCKDEV}..."
  parted -s /dev/${BLOCKDEV} mklabel gpt || {
    log "Failed to create GPT partition table."
    exit 1
  }

  # Create partitions
  log "Creating partitions on /dev/${BLOCKDEV}..."
  if ! parted -s /dev/${BLOCKDEV} "mkpart zosboot fat16 1MiB 100MiB set 1 esp on mkpart zoscache btrfs 100MiB 100%"; then
    log "Failed to create partitions."
    exit 1
  fi

  # Format partitions
  log "Formatting /dev/${PARTPREFIX}1 as FAT32..."
  if ! mkfs.vfat -F32 -nZOSPXE /dev/${PARTPREFIX}1; then
    log "Failed to format /dev/${PARTPREFIX}1 as FAT32."
    exit 1
  fi

  log "Formatting /dev/${PARTPREFIX}2 as BTRFS..."
  if ! mkfs.btrfs -f /dev/${PARTPREFIX}2 -LZOSCACHE; then
    log "Failed to format /dev/${PARTPREFIX}2 as BTRFS."
    exit 1
  fi

  # Mount and prepare directories
  MOUNT_POINT="zospxe"
  log "Creating and mounting directory ./${MOUNT_POINT}..."
  mkdir -p "${MOUNT_POINT}"
  if ! mount /dev/${PARTPREFIX}1 -t vfat "${MOUNT_POINT}"; then
    log "Failed to mount /dev/${PARTPREFIX}1 to ${MOUNT_POINT}."
    exit 1
  fi

  log "Creating directory structure in ${MOUNT_POINT}..."
  mkdir -p "${MOUNT_POINT}/efi/boot"

  # Download the required BOOTX64.EFI file
  # EFI_FILE_URL="https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}"
  EFI_FILE_URL="https://v4.bootstrap.grid.tf/uefi/${ENVIRONMENT}/${FARM}/debug/zero-os-development-zos-v4-rollback-zosbase-debug-9dddfa0299.efi"
  log "Downloading BOOTX64.EFI from ${EFI_FILE_URL}..."
  if ! wget -q "${EFI_FILE_URL}" -O "${MOUNT_POINT}/efi/boot/BOOTX64.EFI"; then
    log "Failed to download BOOTX64.EFI."
    exit 1
  fi

  log "Download successful."

  # Unmount the partition
  log "Unmounting ${MOUNT_POINT}..."
  umount -r "${MOUNT_POINT}" || {
    log "Failed to unmount ${MOUNT_POINT}."
    exit 1
  }

  # Manage UEFI boot entries
  manage_boot_entries

  log "Operation completed successfully."
}

# Execute the main function
main "$@"