#!/bin/bash
#
# Gentoo Kernel Upgrade Script
# This script helps upgrade the gentoo-kernel-bin package safely.
#
# IMPORTANT: This script modifies boot files. A failed upgrade could
# prevent your system from booting. Ensure you have a backup plan.
#

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m' # No Color

EFI_DIR="/boot/efi"
BOOT_DIR="/boot"

# Print functions
info()    { echo -e "${BLUE}==>${NC} ${BOLD}$1${NC}"; }
warn()    { echo -e "${YELLOW}WARNING:${NC} $1"; }
error()   { echo -e "${RED}ERROR:${NC} $1" >&2; }
success() { echo -e "${GREEN}==>${NC} $1"; }

# Check if running as root
check_root() {
    if [[ $EUID -ne 0 ]]; then
        error "This script must be run as root"
        exit 1
    fi
}

# Prompt user for confirmation
confirm() {
    local prompt="$1"
    local response
    echo -e "${YELLOW}${prompt}${NC}"
    read -p "Type 'yes' to confirm: " response
    [[ "$response" == "yes" ]]
}

# Get the currently running kernel version
get_current_version() {
    uname -r
}

# Get the latest installed kernel version from /usr/src
get_latest_installed_version() {
    local latest
    latest=$(ls -1d /usr/src/linux-*-gentoo-dist 2>/dev/null | sort -V | tail -1 | sed 's|.*/linux-||')
    echo "$latest"
}

# Check for available updates using emerge
check_for_updates() {
    info "Checking for gentoo-kernel-bin updates..."
    echo

    # Use emerge to check for updates (pretend mode)
    if emerge -pvu gentoo-kernel-bin 2>/dev/null | grep -q "gentoo-kernel-bin"; then
        local update_info
        update_info=$(emerge -pvu gentoo-kernel-bin 2>/dev/null | grep -E "gentoo-kernel-bin|ebuild")
        echo "$update_info"
        return 0
    else
        return 1
    fi
}

# Install the kernel update
install_kernel_update() {
    info "Installing gentoo-kernel-bin update..."
    echo

    echo -e "${BOLD}The following command will be executed:${NC}"
    echo -e "  ${BLUE}emerge gentoo-kernel-bin${NC}"
    echo

    if ! confirm "Proceed with kernel package installation?"; then
        warn "Installation cancelled by user"
        return 1
    fi

    echo
    emerge gentoo-kernel-bin

    success "Kernel package installed successfully"
}

# Select the new kernel with eselect
select_kernel() {
    local new_version="$1"

    info "Available kernel versions:"
    eselect kernel list
    echo

    # Find the number corresponding to the new version
    local kernel_num
    kernel_num=$(eselect kernel list | grep "$new_version" | sed 's/.*\[\([0-9]*\)\].*/\1/')

    if [[ -z "$kernel_num" ]]; then
        error "Could not find kernel version $new_version in eselect list"
        echo "Please select the kernel manually:"
        eselect kernel list
        read -p "Enter the number to select: " kernel_num
    fi

    echo -e "${BOLD}The following command will be executed:${NC}"
    echo -e "  ${BLUE}eselect kernel set $kernel_num${NC}"
    echo

    if ! confirm "Set kernel $new_version as active?"; then
        warn "Kernel selection cancelled by user"
        return 1
    fi

    eselect kernel set "$kernel_num"

    # Verify
    info "Current kernel symlink:"
    eselect kernel list | grep '\*'
    echo
}

# Backup current boot files
backup_boot_files() {
    info "Backing up current boot files..."

    echo -e "${BOLD}The following operations will be performed in ${EFI_DIR}:${NC}"
    echo -e "  ${BLUE}mv vmlinuz.efi -> vmlinuz.efi.bak${NC}"
    echo -e "  ${BLUE}mv initramfs.img -> initramfs.img.bak${NC}"
    echo

    if [[ -f "${EFI_DIR}/vmlinuz.efi.bak" ]] || [[ -f "${EFI_DIR}/initramfs.img.bak" ]]; then
        warn "Existing backup files will be overwritten!"
    fi

    if ! confirm "Backup current boot files?"; then
        warn "Backup cancelled by user"
        return 1
    fi

    cd "${EFI_DIR}"

    if [[ -f "vmlinuz.efi" ]]; then
        mv vmlinuz.efi vmlinuz.efi.bak
        success "Backed up vmlinuz.efi"
    fi

    if [[ -f "initramfs.img" ]]; then
        mv initramfs.img initramfs.img.bak
        success "Backed up initramfs.img"
    fi

    echo
}

# Generate new initramfs
generate_initramfs() {
    local version="$1"

    info "Generating new initramfs for kernel ${version}..."
    echo

    echo -e "${BOLD}The following command will be executed:${NC}"
    echo -e "  ${BLUE}${EFI_DIR}/generate_initramfs.sh ${version} ${EFI_DIR}/initramfs.img${NC}"
    echo

    if ! confirm "Generate initramfs?"; then
        warn "Initramfs generation cancelled by user"
        return 1
    fi

    bash "${EFI_DIR}/generate_initramfs.sh" "${version}" "${EFI_DIR}/initramfs.img"

    success "Initramfs generated successfully"
    echo
}

# Copy new kernel to EFI partition
copy_kernel() {
    local version="$1"
    local kernel_source="${BOOT_DIR}/kernel-${version}"

    info "Copying new kernel to EFI partition..."
    echo

    if [[ ! -f "$kernel_source" ]]; then
        error "Kernel file not found: $kernel_source"
        return 1
    fi

    echo -e "${BOLD}The following command will be executed:${NC}"
    echo -e "  ${BLUE}cp ${kernel_source} ${EFI_DIR}/vmlinuz.efi${NC}"
    echo

    if ! confirm "Copy new kernel to EFI partition?"; then
        warn "Kernel copy cancelled by user"
        return 1
    fi

    cp "$kernel_source" "${EFI_DIR}/vmlinuz.efi"

    success "Kernel copied successfully"
    echo
}

# Cleanup old kernel versions from /boot
cleanup_old_versions() {
    info "Checking for old kernel versions to clean up..."
    echo

    # Find old initramfs and kernel files (excluding current version)
    local initramfs_to_delete=()
    local kernels_to_delete=()

    while IFS= read -r f; do
        initramfs_to_delete+=("$f")
    done < <(ls ${BOOT_DIR}/initramfs-*.img 2>/dev/null | grep -v "$current_version" || true)

    while IFS= read -r f; do
        kernels_to_delete+=("$f")
    done < <(ls ${BOOT_DIR}/kernel-* 2>/dev/null | grep -v "$current_version" || true)

    # Check if there's anything to delete
    if [[ ${#initramfs_to_delete[@]} -eq 0 ]] && [[ ${#kernels_to_delete[@]} -eq 0 ]]; then
        success "No old kernel versions to clean up"
        echo
        return 0
    fi

    echo -e "${BOLD}The following files will be DELETED:${NC}"
    echo
    for f in "${initramfs_to_delete[@]}" "${kernels_to_delete[@]}"; do
        echo -e "  ${RED}$f${NC}"
    done
    echo

    warn "This action cannot be undone!"
    echo

    if ! confirm "Delete these old kernel files?"; then
        warn "Cleanup cancelled by user"
        return 1
    fi

    echo
    for f in "${initramfs_to_delete[@]}" "${kernels_to_delete[@]}"; do
        rm -v "$f"
    done

    echo
    success "Old kernel versions cleaned up"
    echo
}

# Print summary of what will be done
print_summary() {
    local current="$1"
    local new="$2"

    echo
    echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BOLD}║              GENTOO KERNEL UPGRADE SUMMARY                     ║${NC}"
    echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}"
    echo
    echo -e "  Current running kernel:  ${YELLOW}${current}${NC}"
    echo -e "  New kernel version:      ${GREEN}${new}${NC}"
    echo
    echo -e "${BOLD}The following steps will be performed:${NC}"
    echo "  1. Backup current vmlinuz.efi and initramfs.img"
    echo "  2. Generate new initramfs using dracut"
    echo "  3. Copy new kernel to EFI partition"
    echo
    echo -e "${RED}${BOLD}WARNING: This process modifies boot files!${NC}"
    echo -e "${RED}If something goes wrong, your system may not boot.${NC}"
    echo -e "${RED}Make sure you have a way to recover (live USB, backup, etc.)${NC}"
    echo
}

# Main function
main() {
    echo
    echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BOLD}║           GENTOO KERNEL UPGRADE HELPER                         ║${NC}"
    echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}"
    echo

    check_root

    local current_version
    current_version=$(get_current_version)
    info "Currently running kernel: ${current_version}"
    echo

    # Check for updates
    if ! check_for_updates; then
        success "No updates available for gentoo-kernel-bin"
        echo

        local latest_installed
        latest_installed=$(get_latest_installed_version)

        if [[ "$latest_installed" != "$current_version" ]] && [[ -n "$latest_installed" ]]; then
            # Installed kernel differs from running - offer to set up boot files
            warn "Installed kernel ($latest_installed) differs from running kernel ($current_version)"
            echo
            if confirm "Would you like to set up boot files for $latest_installed?"; then
                print_summary "$current_version" "$latest_installed"

                if ! confirm "Proceed with the upgrade process?"; then
                    echo "Upgrade cancelled."
                    exit 0
                fi

                select_kernel "$latest_installed"
                backup_boot_files
                generate_initramfs "$latest_installed"
                copy_kernel "$latest_installed"

                echo
                success "Kernel upgrade complete!"
                echo
                echo -e "${BOLD}Next steps:${NC}"
                echo "  1. Reboot your system"
                echo "  2. Verify the new kernel is running: uname -r"
                echo "  3. Run this script again to clean up old versions"
                echo
            fi
        else
            # Running kernel is the newest - offer cleanup
            cleanup_old_versions
        fi
        exit 0
    fi

    echo
    if ! confirm "Would you like to install this kernel update?"; then
        echo "Update cancelled."
        exit 0
    fi

    echo
    install_kernel_update

    # Get the new version after installation
    local new_version
    new_version=$(get_latest_installed_version)

    if [[ -z "$new_version" ]]; then
        error "Could not determine new kernel version"
        exit 1
    fi

    print_summary "$current_version" "$new_version"

    if ! confirm "Proceed with the upgrade process?"; then
        echo "Upgrade process cancelled. Kernel package is installed but boot files unchanged."
        exit 0
    fi

    echo
    select_kernel "$new_version"
    backup_boot_files
    generate_initramfs "$new_version"
    copy_kernel "$new_version"

    echo
    success "Kernel upgrade complete!"
    echo
    echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BOLD}║                         NEXT STEPS                             ║${NC}"
    echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}"
    echo
    echo "  1. ${YELLOW}Reboot your system${NC}"
    echo "  2. Verify the new kernel is running:"
    echo "       uname -r"
    echo "     Expected: ${GREEN}${new_version}${NC}"
    echo
    echo "  3. If the new kernel works correctly, run this script again"
    echo "     to clean up old versions"
    echo
    echo "  4. ${RED}If the system fails to boot:${NC}"
    echo "     - Boot from a live USB"
    echo "     - Mount your EFI partition"
    echo "     - Restore backups:"
    echo "         mv vmlinuz.efi.bak vmlinuz.efi"
    echo "         mv initramfs.img.bak initramfs.img"
    echo
}

main "$@"
