#!/bin/bash

# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.

# Usage:
#     so-nsm-cleanup
#
# Options:
#     None - script automatically detects and cleans NVMe devices
#
# Examples:
#     1. Clean NVMe devices and LVM configuration:
#         ```bash
#         sudo so-nsm-cleanup
#         ```
#
# Notes:
#     - Requires root privileges
#     - CAUTION: This script will destroy all data on NVMe devices
#     - Removes:
#         * /nsm mount point
#         * LVM configuration
#         * Partitions and signatures
#     - Safe to run multiple times
#
# Description:
#     This script cleans up NVMe devices and LVM configuration to prepare
#     for testing so-nsm-mount. It performs these steps:
#
#     1. Safety Checks:
#        - Verifies root privileges
#        - Detects NVMe devices
#        - Warns about data loss
#
#     2. Cleanup Operations:
#        - Unmounts and removes /nsm
#        - Removes LVM configuration
#        - Cleans partitions and signatures
#        - Zeros out partition tables
#
# Exit Codes:
#     0: Success - cleanup completed
#     1: Error conditions:
#        - Must be run as root
#        - No NVMe devices found
#        - Cleanup operation failed
#
# Logging:
#     - All operations logged to both console and /opt/so/log/so-nsm-cleanup.log

set -e

LOG_FILE="/opt/so/log/so-nsm-cleanup.log"
MOUNT_POINT="/nsm"
VG_NAME="system"
LV_NAME="nsm"

# Function to log messages
log() {
    local msg="$(date '+%Y-%m-%d %H:%M:%S') $1"
    echo "$msg" | tee -a "$LOG_FILE"
}

# Function to log command output
log_cmd() {
    local cmd="$1"
    local output
    output=$($cmd 2>&1)
    if [ -n "$output" ]; then
        log "$2:"
        echo "$output" | while IFS= read -r line; do
            log "  $line"
        done
    fi
}

# Function to check if running as root
check_root() {
    if [ "$EUID" -ne 0 ]; then
        log "Error: Failed to execute - script must be run as root"
        exit 1
    fi
}

# Function to detect NVMe devices
detect_nvme_devices() {
    local -a devices=()
    
    {
        log "----------------------------------------"
        log "Starting NVMe device detection"
        log "----------------------------------------"
        
        # Get list of NVMe devices
        while read -r dev; do
            if [[ -b "$dev" ]]; then
                devices+=("$dev")
            fi
        done < <(find /dev -name 'nvme*n1' 2>/dev/null)
        
        if [ ${#devices[@]} -eq 0 ]; then
            log "Error: No NVMe devices found"
            log "----------------------------------------"
            exit 1
        fi
        
        log "Found ${#devices[@]} NVMe device(s):"
        for dev in "${devices[@]}"; do
            local size=$(lsblk -dbn -o SIZE "$dev" 2>/dev/null | numfmt --to=iec)
            log "  - $dev ($size)"
        done
        log "----------------------------------------"
    } >&2
    
    # Only output device paths to stdout
    printf '%s\n' "${devices[@]}"
}

# Function to cleanup mount point
cleanup_mount() {
    log "Cleaning up mount point $MOUNT_POINT"
    
    if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
        log "  Unmounting $MOUNT_POINT"
        if ! umount "$MOUNT_POINT" 2>/dev/null; then
            log "  WARNING: Failed to unmount $MOUNT_POINT"
            return 1
        fi
        log "  Successfully unmounted"
    else
        log "  Not mounted - skipping unmount"
    fi
    
    if [[ -d "$MOUNT_POINT" ]]; then
        log "  Removing directory"
        rm -rf "$MOUNT_POINT"
        log "  Directory removed"
    fi
    
    return 0
}

# Function to cleanup LVM
cleanup_lvm() {
    log "Cleaning up LVM configuration"
    
    # Remove logical volume if it exists
    if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then
        log "  Removing logical volume $VG_NAME/$LV_NAME"
        if ! lvremove -f "$VG_NAME/$LV_NAME" 2>/dev/null; then
            log "  WARNING: Failed to remove logical volume"
        else
            log "  Logical volume removed"
        fi
    fi
    
    # Remove volume group if it exists
    if vgs "$VG_NAME" &>/dev/null; then
        log "  Removing volume group $VG_NAME"
        if ! vgremove -f "$VG_NAME" 2>/dev/null; then
            log "  WARNING: Failed to remove volume group"
        else
            log "  Volume group removed"
        fi
    fi
}

# Function to cleanup a device
cleanup_device() {
    local device=$1
    
    if [[ ! -b "$device" ]]; then
        log "ERROR: Invalid device path: $device"
        return 1
    fi
    
    local size=$(lsblk -dbn -o SIZE "$device" 2>/dev/null | numfmt --to=iec)
    log "Processing device: $device ($size)"
    
    # Remove physical volume if it exists
    if pvs "$device" &>/dev/null; then
        log "  Removing physical volume"
        if ! pvremove -ff -y "$device" 2>/dev/null; then
            log "  WARNING: Failed to remove physical volume"
        else
            log "  Physical volume removed"
        fi
    fi
    
    # Clean all signatures and partitions
    log "  Cleaning signatures and partitions"
    if ! wipefs -a "$device" 2>/dev/null; then
        log "  WARNING: Failed to clean signatures"
    else
        log "  Signatures cleaned"
    fi
    
    # Zero out partition table
    log "  Zeroing partition table"
    if ! dd if=/dev/zero of="$device" bs=1M count=10 status=none; then
        log "  WARNING: Failed to zero partition table"
    else
        log "  Partition table zeroed"
    fi
    
    log "  Device cleanup completed"
}

# Main function
main() {
    check_root
    
    log "Starting NVMe device cleanup"
    log "WARNING: This will destroy all data on NVMe devices!"
    log ""
    
    # Log initial system state
    log "Initial system state:"
    log_cmd "lsblk" "Block devices"
    log_cmd "pvs" "Physical volumes"
    log_cmd "vgs" "Volume groups"
    log_cmd "lvs" "Logical volumes"
    log ""
    
    # Clean up mount point
    cleanup_mount
    
    # Clean up LVM configuration
    cleanup_lvm
    
    # Detect and clean up devices
    local -a devices=()
    mapfile -t devices < <(detect_nvme_devices)
    
    log "Starting device cleanup"
    for device in "${devices[@]}"; do
        cleanup_device "$device"
    done
    
    # Log final system state
    log ""
    log "Final system state:"
    log_cmd "lsblk" "Block devices"
    log_cmd "pvs" "Physical volumes"
    log_cmd "vgs" "Volume groups"
    log_cmd "lvs" "Logical volumes"
    
    log ""
    log "Cleanup completed successfully"
}

# Run main function
main "$@"
