#!/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, sdb)."
	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 suitable block devices
find_blockdev() {
	# Minimum size in bytes, e.g., 10 GiB
	MIN_SIZE=$((10 * 1024 * 1024 * 1024))

	BLOCKDEVICES=()

	# Exclude the boot disk
	BOOT_DISK=$(findmnt -n -o SOURCE / | sed 's/[0-9]*$//;s|^/dev/||')
	log "Boot disk detected: /dev/${BOOT_DISK}"

	# Search for NVMe devices first
	log "Searching for NVMe devices..."
	for DEV in /dev/nvme*n1; do
		DEV_BASE=$(basename "$DEV")
		if [ -b "$DEV" ] && [ "$DEV_BASE" != "$BOOT_DISK" ]; then
			SIZE_BYTES=$(blockdev --getsize64 "$DEV")
			if [ "$SIZE_BYTES" -ge "$MIN_SIZE" ]; then
				log "Found NVMe device: $DEV ($(numfmt --to=iec $SIZE_BYTES))"
				BLOCKDEVICES+=("$DEV_BASE")
			else
				log "$DEV is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
			fi
		else
			[ "$DEV_BASE" == "$BOOT_DISK" ] && log "Skipping boot disk: $DEV"
		fi
	done

	# Search for SSD devices
	log "Searching for SSD devices..."
	for DEV_PATH in /sys/block/*; do
		DEV_NAME=$(basename "$DEV_PATH")
		# Exclude unwanted devices and the boot disk
		case "$DEV_NAME" in
		loop* | ram* | sr* | fd* | md* | dm-*)
			continue
			;;
		"$BOOT_DISK")
			log "Skipping boot disk: /dev/$DEV_NAME"
			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))"
				BLOCKDEVICES+=("$DEV_NAME")
			else
				log "$DEVICE is smaller than $(numfmt --to=iec $MIN_SIZE). Skipping."
			fi
		fi
	done

	if [ ${#BLOCKDEVICES[@]} -eq 0 ]; then
		log "No suitable block devices found."
		return 1
	fi

	log "List of block devices to be wiped:"
	for DEV in "${BLOCKDEVICES[@]}"; do
		log "/dev/$DEV"
	done

	# Select the first device as the block device to partition
	BLOCKDEV="${BLOCKDEVICES[0]}"
}

# 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##*/}"
		BLOCKDEVICES=("$BLOCKDEV")
		log "Using specified block device: $BLOCKDEV_SPECIFIED"
	else
		# Find suitable block devices
		if ! find_blockdev; then
			log "Error: No suitable block devices found."
			exit 1
		fi
	fi

	# Confirm with the user before proceeding
	log "The following disks will be wiped:"
	for DEV in "${BLOCKDEVICES[@]}"; do
		log "/dev/$DEV"
	done
	read -p "This will erase all data on the above disks. Are you sure you want to proceed? Type 'WIPE ALL' to confirm: " CONFIRM
	if [ "$CONFIRM" != "WIPE ALL" ]; then
		log "Operation cancelled by user."
		exit 0
	fi

	# Wipe filesystem signatures on all disks
	log "Wiping filesystem signatures on all selected disks..."
	for DEV in "${BLOCKDEVICES[@]}"; do
		log "Wiping /dev/$DEV..."
		wipefs -a -f /dev/$DEV || {
			log "Failed to wipe /dev/$DEV"
			exit 1
		}
	done

	# Proceed with partitioning and formatting the first disk
	# Determine partition naming convention
	if [[ $BLOCKDEV =~ [0-9]$ ]]; then
		PARTPREFIX="${BLOCKDEV}p"
	else
		PARTPREFIX="${BLOCKDEV}"
	fi

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

	# Create BIOS Boot Partition
	log "Creating BIOS Boot partition on /dev/${BLOCKDEV}..."
	parted -s /dev/${BLOCKDEV} mkpart primary 1MiB 2MiB || {
		log "Failed to create BIOS Boot partition."
		exit 1
	}
	parted -s /dev/${BLOCKDEV} set 1 bios_grub on

	# Create additional partitions as needed
	log "Creating data partitions on /dev/${BLOCKDEV}..."
	parted -s /dev/${BLOCKDEV} mkpart primary 2MiB 100MiB || {
		log "Failed to create partition."
		exit 1
	}
	parted -s /dev/${BLOCKDEV} mkpart primary 100MiB 100% || {
		log "Failed to create partition."
		exit 1
	}

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

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

	# Install iPXE bootloader to MBR
	log "Installing iPXE bootloader to MBR of /dev/${BLOCKDEV}..."

	# Download the iPXE bootloader suitable for BIOS
	log "Downloading iPXE bootloader..."
	if ! wget -q -O ipxe.lkrn http://boot.ipxe.org/ipxe.lkrn; then
		log "Failed to download iPXE bootloader."
		exit 1
	fi

	# Write iPXE bootloader to the MBR
	log "Writing iPXE bootloader to MBR of /dev/${BLOCKDEV}..."
	dd if=ipxe.lkrn of=/dev/${BLOCKDEV} bs=440 count=1 conv=notrunc || {
		log "Failed to write iPXE to MBR."
		exit 1
	}

	# Clean up the downloaded file
	rm -f ipxe.lkrn

	# Prepare the iPXE script
	log "Preparing iPXE script..."

	# Mount the FAT16 partition to store the iPXE script
	MOUNT_POINT="zospxe"
	log "Creating and mounting directory ./${MOUNT_POINT}..."
	mkdir -p "${MOUNT_POINT}"
	if ! mount /dev/${PARTPREFIX}2 -t vfat "${MOUNT_POINT}"; then
		log "Failed to mount /dev/${PARTPREFIX}2 to ${MOUNT_POINT}."
		exit 1
	fi

	# Download the BOOTX64.EFI file (optional, depending on your setup)
	# Since this is a BIOS system, we might not need this step
	# However, if required, adjust the script accordingly

	# Alternatively, create an embedded iPXE script
	log "Creating iPXE script..."
	cat >"${MOUNT_POINT}/boot.ipxe" <<EOF
#!ipxe
dhcp
set farm ${FARM}
chain https://bootstrap.grid.tf/uefi/${ENVIRONMENT}/\${FARM}/debug/zero-os-development-zos-v4-debug-7d2de62033.efi?version=v4"
# chain https://bootstrap.grid.tf/ipxe/${ENVIRONMENT}/\${farm}
EOF

	log "iPXE script created at ${MOUNT_POINT}/boot.ipxe"

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

	log "Operation completed successfully."
}

# Execute the main function
main "$@"
