#!/bin/bash
#===============================================================================
# Script: mount_inventory.sh
# Description: Inventaire complet des mounts NFS/CIFS/Virtiofs + bind mounts Docker
# Usage: sudo ./mount_inventory.sh
#===============================================================================

set -o pipefail

# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
BOLD='\033[1m'

# Vérification root
if [[ $EUID -ne 0 ]]; then
    echo -e "${RED}Ce script doit être exécuté avec sudo${NC}"
    exit 1
fi

# Configuration
REAL_USER="${SUDO_USER:-$USER}"
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
HOSTNAME=$(hostname)
OUTPUT_FILE="${REAL_HOME}/mount_inventory_${HOSTNAME}_${TIMESTAMP}.txt"

TOTAL_MOUNTS=0

#===============================================================================
# Fonctions d'affichage
#===============================================================================

output() {
    echo -e "$1"
    echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g' >> "$OUTPUT_FILE"
}

print_header() {
    output ""
    output "${BOLD}${BLUE}═══════════════════════════════════════════════════════════════════════════════${NC}"
    output "${BOLD}${BLUE}  $1${NC}"
    output "${BOLD}${BLUE}═══════════════════════════════════════════════════════════════════════════════${NC}"
}

print_section() {
    output ""
    output "${CYAN}  ┌─────────────────────────────────────────────────────────────────────────────┐${NC}"
    output "${CYAN}  │ $1${NC}"
    output "${CYAN}  └─────────────────────────────────────────────────────────────────────────────┘${NC}"
}

print_subsection() {
    output "${MAGENTA}    ► $1${NC}"
}

print_mount() {
    local type="$1"
    local source="$2"
    local target="$3"
    local indent="${4:-    }"
    
    output "${indent}${GREEN}[${type}]${NC} ${source} ${YELLOW}→${NC} ${target}"
    ((TOTAL_MOUNTS++))
}

print_none() {
    local indent="${1:-    }"
    output "${indent}${YELLOW}(aucun mount trouvé)${NC}"
}

#===============================================================================
# Fonctions de scan des mounts
#===============================================================================

# Analyser les mounts depuis /proc/mounts ou équivalent
# Types: nfs, nfs4, cifs, virtiofs, fuse (pour bindfs)
parse_mounts() {
    local mounts_data="$1"
    local indent="${2:-    }"
    local found=0
    
    while IFS= read -r line; do
        [[ -z "$line" ]] && continue
        
        local source=$(echo "$line" | awk '{print $1}')
        local target=$(echo "$line" | awk '{print $2}')
        local fstype=$(echo "$line" | awk '{print $3}')
        
        case "$fstype" in
            nfs|nfs4)
                print_mount "NFS" "$source" "$target" "$indent"
                found=1
                ;;
            cifs)
                print_mount "CIFS" "$source" "$target" "$indent"
                found=1
                ;;
            virtiofs)
                print_mount "VIRTIOFS" "$source" "$target" "$indent"
                found=1
                ;;
            fuse|fuse.*)
                # Exclure lxcfs et autres fuse système
                if [[ "$source" != "lxcfs" && "$source" != "fusectl" && ! "$target" =~ ^/proc && ! "$target" =~ ^/sys ]]; then
                    print_mount "FUSE" "$source" "$target" "$indent"
                    found=1
                fi
                ;;
        esac
    done <<< "$mounts_data"
    
    return $((1 - found))
}

# Scanner les bind mounts Docker via docker inspect
scan_docker_binds() {
    local docker_cmd="$1"
    local indent="${2:-      }"
    local found=0
    
    # Lister les containers running
    local containers
    containers=$($docker_cmd ps --format '{{.ID}}:{{.Names}}' 2>/dev/null)
    
    if [[ -z "$containers" ]]; then
        output "${indent}${YELLOW}(aucun container Docker en cours d'exécution)${NC}"
        return 1
    fi
    
    while IFS=: read -r cid cname; do
        [[ -z "$cid" ]] && continue
        
        local binds
        binds=$($docker_cmd inspect "$cid" --format '{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}}{{println}}{{end}}' 2>/dev/null)
        
        if [[ -n "$binds" ]]; then
            local container_has_binds=0
            local bind_output=""
            
            while IFS='|' read -r mtype msource mdest; do
                [[ -z "$mtype" ]] && continue
                if [[ "$mtype" == "bind" ]]; then
                    bind_output+="${indent}  ${GREEN}[BIND]${NC} ${msource} ${YELLOW}→${NC} ${mdest}\n"
                    ((TOTAL_MOUNTS++))
                    container_has_binds=1
                    found=1
                fi
            done <<< "$binds"
            
            if [[ $container_has_binds -eq 1 ]]; then
                output "${indent}${CYAN}Container: ${cname}${NC}"
                echo -e "$bind_output" | while IFS= read -r l; do output "$l"; done
            fi
        fi
    done <<< "$containers"
    
    if [[ $found -eq 0 ]]; then
        output "${indent}${YELLOW}(aucun bind mount dans les containers Docker)${NC}"
    fi
    
    return $((1 - found))
}

#===============================================================================
# Scan de l'hôte
#===============================================================================

scan_host() {
    print_header "HÔTE: $HOSTNAME"
    
    print_subsection "Mounts réseau (NFS/CIFS/Virtiofs)"
    local mounts
    mounts=$(cat /proc/mounts 2>/dev/null)
    if ! parse_mounts "$mounts" "    "; then
        print_none "    "
    fi
    
    # Docker sur l'hôte
    if command -v docker &>/dev/null; then
        output ""
        print_subsection "Containers Docker"
        scan_docker_binds "docker" "      "
    fi
    
    # Podman sur l'hôte
    if command -v podman &>/dev/null; then
        output ""
        print_subsection "Containers Podman"
        scan_docker_binds "podman" "      "
    fi
}

#===============================================================================
# Scan des LXC Proxmox
#===============================================================================

scan_proxmox_lxc() {
    command -v pct &>/dev/null || return
    
    local lxc_list
    lxc_list=$(pct list 2>/dev/null | tail -n +2 | awk '$2 == "running" {print $1, $3}')
    
    [[ -z "$lxc_list" ]] && return
    
    print_header "CONTAINERS LXC PROXMOX"
    
    while read -r vmid name; do
        [[ -z "$vmid" ]] && continue
        
        print_section "LXC $vmid: $name"
        
        # 1. Mount points Proxmox (mp0, mp1, etc.)
        print_subsection "Mount Points Proxmox"
        local mp_found=0
        local mp_config
        mp_config=$(pct config "$vmid" 2>/dev/null | grep -E "^mp[0-9]+:")
        
        if [[ -n "$mp_config" ]]; then
            while IFS= read -r mpline; do
                # Format: mp5: /lxc_shares/scripts,mp=/opt/scripts_remote
                local mp_num=$(echo "$mpline" | cut -d: -f1)
                local mp_rest=$(echo "$mpline" | cut -d: -f2- | sed 's/^ *//')
                local mp_source=$(echo "$mp_rest" | cut -d, -f1)
                local mp_target=$(echo "$mp_rest" | grep -oP 'mp=\K[^,]+')
                
                if [[ -n "$mp_target" ]]; then
                    print_mount "MP" "$mp_source" "$mp_target" "      "
                    mp_found=1
                fi
            done <<< "$mp_config"
        fi
        
        [[ $mp_found -eq 0 ]] && print_none "      "
        
        # 2. Mounts réseau dans le container
        output ""
        print_subsection "Mounts réseau dans le container"
        local lxc_mounts
        lxc_mounts=$(pct exec "$vmid" -- cat /proc/mounts 2>/dev/null)
        
        if [[ -n "$lxc_mounts" ]]; then
            if ! parse_mounts "$lxc_mounts" "      "; then
                print_none "      "
            fi
        else
            output "      ${RED}(impossible de lire les mounts)${NC}"
        fi
        
        # 3. Docker dans le LXC
        local has_docker
        has_docker=$(pct exec "$vmid" -- which docker 2>/dev/null)
        
        if [[ -n "$has_docker" ]]; then
            output ""
            print_subsection "Containers Docker dans LXC"
            
            local docker_containers
            docker_containers=$(pct exec "$vmid" -- docker ps --format '{{.ID}}:{{.Names}}' 2>/dev/null)
            
            if [[ -n "$docker_containers" ]]; then
                local docker_found=0
                while IFS=: read -r cid cname; do
                    [[ -z "$cid" ]] && continue
                    
                    local binds
                    binds=$(pct exec "$vmid" -- docker inspect "$cid" --format '{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}}{{println}}{{end}}' 2>/dev/null)
                    
                    if [[ -n "$binds" ]]; then
                        local container_binds=""
                        while IFS='|' read -r mtype msource mdest; do
                            [[ -z "$mtype" ]] && continue
                            if [[ "$mtype" == "bind" ]]; then
                                container_binds+="        ${GREEN}[BIND]${NC} ${msource} ${YELLOW}→${NC} ${mdest}\n"
                                ((TOTAL_MOUNTS++))
                                docker_found=1
                            fi
                        done <<< "$binds"
                        
                        if [[ -n "$container_binds" ]]; then
                            output "      ${CYAN}Container: ${cname}${NC}"
                            echo -e "$container_binds" | while IFS= read -r l; do [[ -n "$l" ]] && output "$l"; done
                        fi
                    fi
                done <<< "$docker_containers"
                
                [[ $docker_found -eq 0 ]] && output "      ${YELLOW}(aucun bind mount)${NC}"
            else
                output "      ${YELLOW}(aucun container Docker en cours)${NC}"
            fi
        fi
        
    done <<< "$lxc_list"
}

#===============================================================================
# Scan des VMs Proxmox
#===============================================================================

scan_proxmox_vms() {
    command -v qm &>/dev/null || return
    
    local vm_list
    vm_list=$(qm list 2>/dev/null | tail -n +2 | awk '$3 == "running" {print $1, $2}')
    
    [[ -z "$vm_list" ]] && return
    
    print_header "MACHINES VIRTUELLES PROXMOX"
    
    while read -r vmid name; do
        [[ -z "$vmid" ]] && continue
        
        print_section "VM $vmid: $name"
        
        # Vérifier si guest agent répond
        local ga_test
        ga_test=$(qm guest exec "$vmid" -- echo "ok" 2>&1)
        
        if [[ "$ga_test" != *"ok"* && "$ga_test" != *'"out-data"'* ]]; then
            output "    ${RED}(QEMU Guest Agent non disponible)${NC}"
            continue
        fi
        
        # Détecter l'OS
        local os_type="linux"
        if [[ "$name" == *"win"* ]] || [[ "$name" == *"Win"* ]]; then
            os_type="windows"
        fi
        
        if [[ "$os_type" == "windows" ]]; then
            output "    ${YELLOW}(VM Windows - scan limité)${NC}"
            continue
        fi
        
        # Mounts réseau dans la VM
        print_subsection "Mounts réseau"
        local vm_mounts_raw
        vm_mounts_raw=$(qm guest exec "$vmid" -- cat /proc/mounts 2>/dev/null)
        
        if [[ -n "$vm_mounts_raw" ]]; then
            # Extraire out-data du JSON
            local vm_mounts
            vm_mounts=$(echo "$vm_mounts_raw" | grep -oP '"out-data"\s*:\s*"\K[^"]+' | sed 's/\\n/\n/g')
            
            if [[ -n "$vm_mounts" ]]; then
                if ! parse_mounts "$vm_mounts" "      "; then
                    print_none "      "
                fi
            else
                print_none "      "
            fi
        else
            output "      ${RED}(impossible de lire les mounts)${NC}"
        fi
        
        # Docker dans la VM
        local has_docker
        has_docker=$(qm guest exec "$vmid" -- which docker 2>&1)
        
        if [[ "$has_docker" == *"/docker"* ]] || [[ "$has_docker" == *"out-data"*"/docker"* ]]; then
            output ""
            print_subsection "Containers Docker dans VM"
            
            # Obtenir la liste des containers
            local docker_ps_raw
            docker_ps_raw=$(qm guest exec "$vmid" -- docker ps --format '{{.ID}}:{{.Names}}' 2>/dev/null)
            
            if [[ -n "$docker_ps_raw" ]]; then
                local docker_ps
                docker_ps=$(echo "$docker_ps_raw" | grep -oP '"out-data"\s*:\s*"\K[^"]+' | sed 's/\\n/\n/g')
                
                if [[ -n "$docker_ps" ]]; then
                    local docker_found=0
                    while IFS=: read -r cid cname; do
                        [[ -z "$cid" ]] && continue
                        
                        local inspect_raw
                        inspect_raw=$(qm guest exec "$vmid" -- docker inspect "$cid" --format '{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}}{{println}}{{end}}' 2>/dev/null)
                        
                        if [[ -n "$inspect_raw" ]]; then
                            local inspect_data
                            inspect_data=$(echo "$inspect_raw" | grep -oP '"out-data"\s*:\s*"\K[^"]+' | sed 's/\\n/\n/g')
                            
                            local container_binds=""
                            while IFS='|' read -r mtype msource mdest; do
                                [[ -z "$mtype" ]] && continue
                                if [[ "$mtype" == "bind" ]]; then
                                    container_binds+="        ${GREEN}[BIND]${NC} ${msource} ${YELLOW}→${NC} ${mdest}\n"
                                    ((TOTAL_MOUNTS++))
                                    docker_found=1
                                fi
                            done <<< "$inspect_data"
                            
                            if [[ -n "$container_binds" ]]; then
                                output "      ${CYAN}Container: ${cname}${NC}"
                                echo -e "$container_binds" | while IFS= read -r l; do [[ -n "$l" ]] && output "$l"; done
                            fi
                        fi
                    done <<< "$docker_ps"
                    
                    [[ $docker_found -eq 0 ]] && output "      ${YELLOW}(aucun bind mount)${NC}"
                else
                    output "      ${YELLOW}(aucun container Docker en cours)${NC}"
                fi
            else
                output "      ${YELLOW}(aucun container Docker en cours)${NC}"
            fi
        fi
        
    done <<< "$vm_list"
}

#===============================================================================
# Résumé
#===============================================================================

print_summary() {
    output ""
    output "${BOLD}${BLUE}═══════════════════════════════════════════════════════════════════════════════${NC}"
    output "${BOLD}${BLUE}  RÉSUMÉ${NC}"
    output "${BOLD}${BLUE}═══════════════════════════════════════════════════════════════════════════════${NC}"
    output ""
    output "  ${GREEN}Total des mounts trouvés: $TOTAL_MOUNTS${NC}"
    output ""
    output "  ${CYAN}Fichier sauvegardé: $OUTPUT_FILE${NC}"
    output ""
}

#===============================================================================
# Main
#===============================================================================

main() {
    # Initialiser fichier
    cat > "$OUTPUT_FILE" << EOF
=================================================================================
  INVENTAIRE DES MOUNTS - $HOSTNAME
  Date: $(date)
  Utilisateur: $REAL_USER
=================================================================================

EOF
    
    echo -e "${GREEN}[INFO]${NC} Démarrage de l'inventaire des mounts sur $HOSTNAME"
    echo -e "${GREEN}[INFO]${NC} Types: NFS, CIFS, Virtiofs, FUSE, Bind mounts Docker"
    echo ""
    
    scan_host
    scan_proxmox_lxc
    scan_proxmox_vms
    print_summary
    
    chown "$REAL_USER:$REAL_USER" "$OUTPUT_FILE" 2>/dev/null || true
}

main "$@"
