#!/bin/bash

# Configuración
SCRIPT_VERSION="1.3"
LOG_FILE="/var/log/proxmox_backup_restore.log"

# Colores para salida
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

# Variable global para el modo de interfaz
INTERFACE_MODE=""

# Funciones de utilidad
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
    echo -e "$1"
}

error() {
    log "${RED}ERROR: $1${NC}"
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        whiptail --title "Error" --msgbox "$1" 8 78
    else
        echo -e "${RED}ERROR: $1${NC}"
    fi
    exit 1
}

success() {
    log "${GREEN}$1${NC}"
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        whiptail --title "Éxito" --msgbox "$1" 8 78
    else
        echo -e "${GREEN}$1${NC}"
    fi
}

warning() {
    log "${YELLOW}ADVERTENCIA: $1${NC}"
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        whiptail --title "Advertencia" --msgbox "$1" 8 78
    else
        echo -e "${YELLOW}ADVERTENCIA: $1${NC}"
    fi
}

# Función para seleccionar el modo de interfaz
select_interface_mode() {
    if [ "$(tty)" = "/dev/tty1" ] || [ "$(tty)" = "/dev/console" ]; then
        echo "Ejecutando en consola física. Usando interfaz de texto."
        INTERFACE_MODE="echo"
    elif command -v whiptail >/dev/null 2>&1; then
        echo "Ejecutando en terminal remota. Usando interfaz whiptail."
        INTERFACE_MODE="whiptail"
    else
        echo "whiptail no está disponible. Usando interfaz de texto."
        INTERFACE_MODE="echo"
    fi
}

# Función para mostrar el menú principal
show_main_menu() {
    while true; do
        if [ "$INTERFACE_MODE" = "whiptail" ]; then
            CHOICE=$(whiptail --title "Proxmox Backup & Restore Tool" --menu "Seleccione una opción:" 15 60 3 \
            "1" "Realizar copia de seguridad" \
            "2" "Restaurar copia de seguridad" \
            "3" "Salir" 3>&1 1>&2 2>&3)
        else
            echo "Proxmox Backup & Restore Tool"
            echo "1. Realizar copia de seguridad"
            echo "2. Restaurar copia de seguridad"
            echo "3. Salir"
            read -p "Seleccione una opción: " CHOICE
        fi

        case $CHOICE in
            1) perform_backup ;;
            2) perform_restore ;;
            3) exit 0 ;;
            *) echo "Opción no válida. Por favor, intente de nuevo." ;;
        esac
    done
}

# Función para seleccionar la ubicación de la copia de seguridad
select_backup_location() {
    local options=()
    local i=1

    # Ubicaciones recomendadas
    options+=("/root/backups/" "/var/lib/vz/dump/")

    # Detectar discos USB
    local usb_disks=$(lsblk -ndo NAME,TRAN,SIZE | awk '$2=="usb" {print "/dev/"$1}')
    options+=($usb_disks)

    # Otros discos disponibles
    local other_disks=$(lsblk -ndo NAME,SIZE,FSTYPE | grep -vE "^(sd[a-z]|nvme[0-9]n[0-9])" | awk '$3!="" {print "/dev/"$1}')
    options+=($other_disks)

    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        BACKUP_LOCATION=$(whiptail --title "Seleccionar ubicación de copia de seguridad" \
            --menu "Elija dónde guardar la copia de seguridad:" 20 78 10 \
            $(for i in "${!options[@]}"; do echo "$i ${options[$i]}"; done) \
            "C" "Introducir ruta personalizada" 3>&1 1>&2 2>&3)
    else
        echo "Seleccionar ubicación de copia de seguridad:"
        for i in "${!options[@]}"; do
            echo "$i. ${options[$i]}"
        done
        echo "C. Introducir ruta personalizada"
        read -p "Elija dónde guardar la copia de seguridad: " BACKUP_LOCATION
    fi

    if [[ $BACKUP_LOCATION == "C" ]]; then
        if [ "$INTERFACE_MODE" = "whiptail" ]; then
            BACKUP_LOCATION=$(whiptail --inputbox "Introduzca la ruta personalizada:" 8 78 "/mnt/backup" --title "Ruta personalizada" 3>&1 1>&2 2>&3)
        else
            read -p "Introduzca la ruta personalizada: " BACKUP_LOCATION
        fi
    elif [[ $BACKUP_LOCATION =~ ^[0-9]+$ ]]; then
        BACKUP_LOCATION=${options[$BACKUP_LOCATION]}
    fi

    echo "$BACKUP_LOCATION"
}

# Función para realizar la copia de seguridad
perform_backup() {
    local BACKUP_LOCATION=$(select_backup_location)
    
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        local BACKUP_TYPE=$(whiptail --title "Tipo de copia de seguridad" --menu "Seleccione el tipo de copia de seguridad:" 15 60 2 \
            "1" "Copia de seguridad total" \
            "2" "Copia de seguridad personalizada" 3>&1 1>&2 2>&3)
    else
        echo "Tipo de copia de seguridad:"
        echo "1. Copia de seguridad total"
        echo "2. Copia de seguridad personalizada"
        read -p "Seleccione el tipo de copia de seguridad: " BACKUP_TYPE
    fi

    local TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
    local BACKUP_PATH="${BACKUP_LOCATION}/proxmox_backup_${TIMESTAMP}"
    mkdir -p "$BACKUP_PATH" || error "No se pudo crear el directorio de copia de seguridad."

    case $BACKUP_TYPE in
        1) backup_total "$BACKUP_PATH" ;;
        2) backup_personalizada "$BACKUP_PATH" ;;
        *) error "Opción no válida." ;;
    esac

    # Guardar versión de Proxmox
    pveversion > "$BACKUP_PATH/pve_version.txt"

    # Guardar mapa de rutas de almacenamiento
    pvesm status --output-format=json > "$BACKUP_PATH/storage_paths.json"

    success "Copia de seguridad completada en $BACKUP_PATH"
}

# Función para realizar copia de seguridad total
backup_total() {
    local BACKUP_PATH=$1
    log "Iniciando copia de seguridad total..."

    # Copiar configuraciones de Proxmox
    cp -r /etc/pve "$BACKUP_PATH/etc_pve" || warning "Error al copiar /etc/pve"
    cp -r /etc/network "$BACKUP_PATH/etc_network" || warning "Error al copiar /etc/network"
    cp /etc/hostname "$BACKUP_PATH/etc_hostname" || warning "Error al copiar /etc/hostname"
    cp /etc/hosts "$BACKUP_PATH/etc_hosts" || warning "Error al copiar /etc/hosts"

    # Copiar logs relevantes
    mkdir -p "$BACKUP_PATH/var_log"
    cp /var/log/pveam.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pveam.log"
    cp /var/log/pvedaemon.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pvedaemon.log"

    # Copiar configuraciones de almacenamiento
    cp /etc/pve/storage.cfg "$BACKUP_PATH/storage.cfg" || warning "Error al copiar storage.cfg"

    # Copiar configuraciones de usuarios y permisos
    cp /etc/pve/user.cfg "$BACKUP_PATH/user.cfg" || warning "Error al copiar user.cfg"
    cp /etc/pve/groups.cfg "$BACKUP_PATH/groups.cfg" || warning "Error al copiar groups.cfg"

    # Copiar configuraciones de firewall
    cp -r /etc/pve/firewall "$BACKUP_PATH/firewall" || warning "Error al copiar configuraciones de firewall"

    # Copiar metadatos de VMs y contenedores (sin incluir discos o snapshots)
    mkdir -p "$BACKUP_PATH/vms_metadata"
    for vmid in $(qm list | awk '{if(NR>1) print $1}'); do
        qm config $vmid > "$BACKUP_PATH/vms_metadata/vm_${vmid}.conf"
    done

    mkdir -p "$BACKUP_PATH/cts_metadata"
    for ctid in $(pct list | awk '{if(NR>1) print $1}'); do
        pct config $ctid > "$BACKUP_PATH/cts_metadata/ct_${ctid}.conf"
    done

    log "Copia de seguridad total completada."
}

# Función para realizar copia de seguridad personalizada
backup_personalizada() {
    local BACKUP_PATH=$1
    log "Iniciando copia de seguridad personalizada..."

    local options=(
        "1" "Configuración del sistema Proxmox" ON
        "2" "Configuraciones de almacenamiento" ON
        "3" "Configuraciones de red" ON
        "4" "Usuarios y permisos" ON
        "5" "Logs del sistema relevantes" OFF
        "6" "Configuraciones de firewall" ON
        "7" "Metadatos de VMs y contenedores" ON
    )

    local SELECTED_OPTIONS
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        SELECTED_OPTIONS=$(whiptail --title "Selección de componentes" \
            --checklist "Seleccione los componentes a respaldar:" 20 78 7 \
            "${options[@]}" 3>&1 1>&2 2>&3)
    else
        echo "Selección de componentes a respaldar:"
        for ((i=0; i<${#options[@]}; i+=3)); do
            echo "${options[i]}. ${options[i+1]}"
        done
        read -p "Ingrese los números de los componentes a respaldar (separados por espacio): " -a selections
        for sel in "${selections[@]}"; do
            SELECTED_OPTIONS+="$sel "
        done
    fi

    for option in $SELECTED_OPTIONS; do
        case $option in
            1)
                cp -r /etc/pve "$BACKUP_PATH/etc_pve" || warning "Error al copiar /etc/pve"
                cp /etc/hostname "$BACKUP_PATH/etc_hostname" || warning "Error al copiar /etc/hostname"
                cp /etc/hosts "$BACKUP_PATH/etc_hosts" || warning "Error al copiar /etc/hosts"
                ;;
            2)
                cp /etc/pve/storage.cfg "$BACKUP_PATH/storage.cfg" || warning "Error al copiar storage.cfg"
                ;;
            3)
                cp -r /etc/network "$BACKUP_PATH/etc_network" || warning "Error al copiar /etc/network"
                ;;
            4)
                cp /etc/pve/user.cfg "$BACKUP_PATH/user.cfg" || warning "Error al copiar user.cfg"
                cp /etc/pve/groups.cfg "$BACKUP_PATH/groups.cfg" || warning "Error al copiar groups.cfg"
                ;;
            5)
                mkdir -p "$BACKUP_PATH/var_log"
                cp /var/log/pveam.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pveam.log"
                cp /var/log/pvedaemon.log "$BACKUP_PATH/var_log/" || warning "Error al copiar pvedaemon.log"
                ;;
            6)
                cp -r /etc/pve/firewall "$BACKUP_PATH/firewall" || warning "Error al copiar configuraciones de firewall"
                ;;
            7)
                mkdir -p "$BACKUP_PATH/vms_metadata"
                for vmid in $(qm list | awk '{if(NR>1) print $1}'); do
                    qm config $vmid > "$BACKUP_PATH/vms_metadata/vm_${vmid}.conf"
                done

                mkdir -p "$BACKUP_PATH/cts_metadata"
                for ctid in $(pct list | awk '{if(NR>1) print $1}'); do
                    pct config $ctid > "$BACKUP_PATH/cts_metadata/ct_${ctid}.conf"
                done
                ;;
        esac
    done

    log "Copia de seguridad personalizada completada."
}

# Función para restaurar desde una copia de seguridad
perform_restore() {
    local BACKUP_LOCATION
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        BACKUP_LOCATION=$(whiptail --inputbox "Introduzca la ruta de la copia de seguridad:" 8 78 "/root/proxmox_backups" --title "Restauración" 3>&1 1>&2 2>&3)
    else
        read -p "Introduzca la ruta de la copia de seguridad: " BACKUP_LOCATION
    fi

    local backups=($(ls -d ${BACKUP_LOCATION}/proxmox_backup_* 2>/dev/null))
    if [ ${#backups[@]} -eq 0 ]; then
        error "No se encontraron copias de seguridad en $BACKUP_LOCATION"
    fi

    local SELECTED_BACKUP
    if [ "$INTERFACE_MODE" = "whiptail" ]; then
        local options=()
        for i in "${!backups[@]}"; do
            options+=("$i" "$(basename ${backups[$i]})")
        done
        SELECTED_BACKUP=$(whiptail --title "Seleccionar copia de seguridad" \
            --menu "Elija la copia de seguridad a restaurar:" 20 78 10 \
            "${options[@]}" 3>&1 1>&2 2>&3)
    else
        echo "Copias de seguridad disponibles:"
        for i in "${!backups[@]}"; do
            echo "$i. $(basename ${backups[$i]})"
        done
        read -p "Elija la copia de seguridad a restaurar: " SELECTED_BACKUP
    fi

    local BACKUP_PATH="${backups[$SELECTED_BACKUP]}"

    # Verificar compatibilidad de versiones
    if ! verify_pve_version "$BACKUP_PATH"; then
        if [ "$INTERFACE_MODE" = "whiptail" ]; then
            if ! whiptail --yesno "La versión de Proxmox es diferente. ¿Desea continuar con la restauración?" 8 78; then
                error "Restauración cancelada debido a diferencia de versiones."
            fi
        else
            read -p "La versión de Proxmox es diferente. ¿Desea continuar con la restauración? (s/n): " response
            if [[ ! $response =~ ^[Ss]$ ]]; then
                error "Restauración cancelada debido a diferencia de versiones."
            fi
        fi
    fi

    # Verificar cambios de hardware
    if ! verify_hardware "$BACKUP_PATH"; then
        warning "Se detectaron cambios en el hardware. Revise el informe en $BACKUP_PATH/hardware_changes.txt"
    fi

    # Verificar y ajustar paths de almacenamiento
    if ! adjust_storage_paths "$BACKUP_PATH"; then
        warning "Algunas rutas de almacenamiento han cambiado. Revise y ajuste manualmente si es necesario."
    fi

    # Realizar la restauración
    restore_files "$BACKUP_PATH"

    success "Restauración completada. Se recomienda reiniciar el sistema."
}

# Función para verificar la versión de Proxmox
verify_pve_version() {
    local BACKUP_PATH=$1
    local backup_version=$(cat "$BACKUP_PATH/pve_version.txt")
    local current_version=$(pveversion | grep "pve-manager/")

    if [ "$backup_version" != "$current_version" ]; then
        warning "La versión de Proxmox actual ($current_version) es diferente de la versión del backup ($backup_version)."
        return 1
    fi
    return 0
}

# Función para verificar cambios de hardware
verify_hardware() {
    local BACKUP_PATH=$1
    local current_hw=$(lshw -short)
    local backup_hw_file="$BACKUP_PATH/hardware_info.txt"

    if [ ! -f "$backup_hw_file" ]; then
        warning "No se encontró información de hardware en la copia de seguridad."
        return 1
    fi

    local backup_hw=$(cat "$backup_hw_file")
    if [ "$current_hw" != "$backup_hw" ]; then
        diff <(echo "$backup_hw") <(echo "$current_hw") > "$BACKUP_PATH/hardware_changes.txt"
        return 1
    fi
    return 0
}

# Función para ajustar rutas de almacenamiento
adjust_storage_paths() {
    local BACKUP_PATH=$1
    local old_paths_file="$BACKUP_PATH/storage_paths.json"
    local new_paths=$(pvesm status --output-format=json)

    if [ ! -f "$old_paths_file" ]; then
        warning "No se encontró información de rutas de almacenamiento en la copia de seguridad."
        return 1
    fi

    local old_paths=$(cat "$old_paths_file")
    if [ "$new_paths" != "$old_paths" ]; then
        echo "Se detectaron cambios en las rutas de almacenamiento:"
        diff <(echo "$old_paths") <(echo "$new_paths")
        
        if [ "$INTERFACE_MODE" = "whiptail" ]; then
            if whiptail --yesno "¿Desea ajustar automáticamente las rutas de almacenamiento?" 8 78; then
                # Aquí iría la lógica para ajustar automáticamente las rutas
                # Por ejemplo, actualizando los archivos de configuración relevantes
                warning "Ajuste automático de rutas no implementado. Por favor, revise manualmente."
            else
                warning "Las rutas de almacenamiento deben ajustarse manualmente."
            fi
        else
            read -p "¿Desea ajustar automáticamente las rutas de almacenamiento? (s/n): " response
            if [[ $response =~ ^[Ss]$ ]]; then
                # Aquí iría la lógica para ajustar automáticamente las rutas
                warning "Ajuste automático de rutas no implementado. Por favor, revise manualmente."
            else
                warning "Las rutas de almacenamiento deben ajustarse manualmente."
            fi
        fi
        return 1
    fi
    return 0
}

# Función para restaurar archivos
restore_files() {
    local BACKUP_PATH=$1
    log "Iniciando restauración de archivos..."

    # Restaurar configuraciones de Proxmox
    if [ -d "$BACKUP_PATH/etc_pve" ]; then
        cp -r "$BACKUP_PATH/etc_pve"/* /etc/pve/ || warning "Error al restaurar /etc/pve"
    fi

    if [ -d "$BACKUP_PATH/etc_network" ]; then
        cp -r "$BACKUP_PATH/etc_network"/* /etc/network/ || warning "Error al restaurar /etc/network"
    fi

    if [ -f "$BACKUP_PATH/etc_hostname" ]; then
        cp "$BACKUP_PATH/etc_hostname" /etc/hostname || warning "Error al restaurar /etc/hostname"
    fi

    if [ -f "$BACKUP_PATH/etc_hosts" ]; then
        cp "$BACKUP_PATH/etc_hosts" /etc/hosts || warning "Error al restaurar /etc/hosts"
    fi

    # Restaurar logs
    if [ -d "$BACKUP_PATH/var_log" ]; then
        cp "$BACKUP_PATH/var_log"/* /var/log/ || warning "Error al restaurar logs"
    fi

    # Restaurar configuraciones de almacenamiento
    if [ -f "$BACKUP_PATH/storage.cfg" ]; then
        cp "$BACKUP_PATH/storage.cfg" /etc/pve/storage.cfg || warning "Error al restaurar storage.cfg"
    fi

    # Restaurar configuraciones de usuarios y permisos
    if [ -f "$BACKUP_PATH/user.cfg" ]; then
        cp "$BACKUP_PATH/user.cfg" /etc/pve/user.cfg || warning "Error al restaurar user.cfg"
    fi

    if [ -f "$BACKUP_PATH/groups.cfg" ]; then
        cp "$BACKUP_PATH/groups.cfg" /etc/pve/groups.cfg || warning "Error al restaurar groups.cfg"
    fi

    # Restaurar configuraciones de firewall
    if [ -d "$BACKUP_PATH/firewall" ]; then
        cp -r "$BACKUP_PATH/firewall"/* /etc/pve/firewall/ || warning "Error al restaurar configuraciones de firewall"
    fi

    # Restaurar metadatos de VMs y contenedores
    if [ -d "$BACKUP_PATH/vms_metadata" ]; then
        for conf in "$BACKUP_PATH/vms_metadata"/*.conf; do
            vmid=$(basename "$conf" .conf | cut -d'_' -f2)
            qm importconfig $vmid "$conf" || warning "Error al restaurar configuración de VM $vmid"
        done
    fi

    if [ -d "$BACKUP_PATH/cts_metadata" ]; then
        for conf in "$BACKUP_PATH/cts_metadata"/*.conf; do
            ctid=$(basename "$conf" .conf | cut -d'_' -f2)
            pct importconfig $ctid "$conf" || warning "Error al restaurar configuración de CT $ctid"
        done
    fi

    log "Restauración de archivos completada."
}

# Iniciar el script
select_interface_mode
show_main_menu
