#!/usr/bin/env bash
# List all private IP address assignments in Proxmox
# Works both via API (remote) and direct commands (on Proxmox host)

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Try to load environment if available
if [[ -f "$SCRIPT_DIR/load-env.sh" ]]; then
    source "$SCRIPT_DIR/load-env.sh"
    load_env_file 2>/dev/null || true
fi

PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}"
PROXMOX_PORT="${PROXMOX_PORT:-8006}"

# Check if running on Proxmox host
ON_PROXMOX_HOST=false
if command -v pct >/dev/null 2>&1 && command -v qm >/dev/null 2>&1; then
    ON_PROXMOX_HOST=true
fi

# Function to check if IP is private
is_private_ip() {
    local ip="$1"
    # Private IP ranges:
    # 10.0.0.0/8
    # 172.16.0.0/12
    # 192.168.0.0/16
    if [[ "$ip" =~ ^10\. ]] || \
       [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[0-1])\. ]] || \
       [[ "$ip" =~ ^192\.168\. ]]; then
        return 0
    fi
    return 1
}

# Function to get LXC container IP from config
get_lxc_config_ip() {
    local vmid="$1"
    local config_file="/etc/pve/lxc/${vmid}.conf"
    
    if [[ -f "$config_file" ]]; then
        # Extract IP from net0: or net1: lines
        local ip=$(grep -E "^net[0-9]+:" "$config_file" 2>/dev/null | \
                   grep -oE 'ip=([0-9]{1,3}\.){3}[0-9]{1,3}' | \
                   cut -d'=' -f2 | head -1)
        if [[ -n "$ip" ]]; then
            # Remove CIDR notation if present
            echo "${ip%/*}"
        fi
    fi
}

# Function to get LXC container actual IP (if running)
get_lxc_actual_ip() {
    local vmid="$1"
    
    if ! pct status "$vmid" 2>/dev/null | grep -q "status: running"; then
        return
    fi
    
    # Try to get IP from container
    local ip=$(timeout 3s pct exec "$vmid" -- ip -4 addr show 2>/dev/null | \
               grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+' | \
               grep -v '127.0.0.1' | head -1 | cut -d'/' -f1)
    
    if [[ -n "$ip" ]]; then
        echo "$ip"
    fi
}

# Function to get VM IP from config (cloud-init or static)
get_vm_config_ip() {
    local vmid="$1"
    local config_file="/etc/pve/qemu-server/${vmid}.conf"
    
    if [[ -f "$config_file" ]]; then
        # Check for cloud-init IP configuration
        local ip=$(grep -E "^ipconfig[0-9]+:" "$config_file" 2>/dev/null | \
                   grep -oE 'ip=([0-9]{1,3}\.){3}[0-9]{1,3}' | \
                   cut -d'=' -f2 | head -1)
        if [[ -n "$ip" ]]; then
            echo "${ip%/*}"
        fi
    fi
}

# Function to get VM actual IP via guest agent
get_vm_actual_ip() {
    local vmid="$1"
    
    if ! qm status "$vmid" 2>/dev/null | grep -q "status: running"; then
        return
    fi
    
    # Try guest agent
    local ip=$(timeout 5s qm guest cmd "$vmid" network-get-interfaces 2>/dev/null | \
               grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
               grep -v "127.0.0.1" | head -1)
    
    if [[ -n "$ip" ]]; then
        echo "$ip"
    fi
}

# Function to get VM IP via ARP table
get_vm_arp_ip() {
    local vmid="$1"
    local config_file="/etc/pve/qemu-server/${vmid}.conf"
    
    if [[ ! -f "$config_file" ]]; then
        return
    fi
    
    # Get MAC address from config
    local mac=$(grep -E "^net[0-9]+:" "$config_file" 2>/dev/null | \
                grep -oE "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}" | head -1)
    
    if [[ -n "$mac" ]]; then
        local ip=$(ip neighbor show 2>/dev/null | grep -i "$mac" | \
                   grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
        if [[ -n "$ip" ]]; then
            echo "$ip"
        fi
    fi
}

# Function to extract IP from config content
extract_ip_from_config() {
    local config_content="$1"
    local type="$2"  # "lxc" or "qemu"
    
    if [[ "$type" == "lxc" ]]; then
        # Extract IP from net0: or net1: lines for LXC
        echo "$config_content" | grep -E "^net[0-9]+:" | \
            grep -oE 'ip=([0-9]{1,3}\.){3}[0-9]{1,3}' | \
            cut -d'=' -f2 | head -1 | sed 's|/.*||'
    else
        # Extract IP from ipconfig0: or ipconfig1: lines for VMs
        echo "$config_content" | grep -E "^ipconfig[0-9]+:" | \
            grep -oE 'ip=([0-9]{1,3}\.){3}[0-9]{1,3}' | \
            cut -d'=' -f2 | head -1 | sed 's|/.*||'
    fi
}

# Function to get config IP via API
get_config_ip_api() {
    local node="$1"
    local vmid="$2"
    local type="$3"  # "qemu" or "lxc"
    
    local config_response=$(curl -k -s -m 5 \
        -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \
        "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/nodes/${node}/${type}/${vmid}/config" 2>/dev/null)
    
    if [[ -z "$config_response" ]]; then
        return
    fi
    
    # Extract IP from JSON config
    if [[ "$type" == "lxc" ]]; then
        # For LXC: extract from net0, net1, etc. fields
        echo "$config_response" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin).get('data', {})
    # Check net0, net1, net2, etc.
    for i in range(10):
        net_key = f'net{i}'
        if net_key in data:
            net_value = data[net_key]
            if 'ip=' in net_value:
                # Extract IP from ip=192.168.11.100/24 format
                import re
                match = re.search(r'ip=([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})', net_value)
                if match:
                    print(match.group(1))
                    break
except:
    pass
" 2>/dev/null
    else
        # For VM: extract from ipconfig0, ipconfig1, etc. fields
        echo "$config_response" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin).get('data', {})
    # Check ipconfig0, ipconfig1, etc.
    for i in range(10):
        ipconfig_key = f'ipconfig{i}'
        if ipconfig_key in data:
            ipconfig_value = data[ipconfig_key]
            if 'ip=' in ipconfig_value:
                # Extract IP from ip=192.168.11.100/24 format
                import re
                match = re.search(r'ip=([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})', ipconfig_value)
                if match:
                    print(match.group(1))
                    break
except:
    pass
" 2>/dev/null
    fi
}

# Function to list IPs via API
list_ips_via_api() {
    local node="$1"
    
    echo "Fetching data from Proxmox API..."
    echo ""
    
    # Get all VMs
    local vms_response=$(curl -k -s -m 10 \
        -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \
        "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/nodes/${node}/qemu" 2>/dev/null)
    
    # Get all LXC containers
    local lxc_response=$(curl -k -s -m 10 \
        -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \
        "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/nodes/${node}/lxc" 2>/dev/null)
    
    echo "VMID    Type    Name                    Status      Config IP        Actual IP"
    echo "--------------------------------------------------------------------------------"
    
    # Process VMs - store in temp file to avoid subshell issues
    local temp_file=$(mktemp)
    echo "$vms_response" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)['data']
    for vm in sorted(data, key=lambda x: x['vmid']):
        vmid = vm['vmid']
        name = vm.get('name', 'N/A')
        status = vm.get('status', 'unknown')
        print(f'{vmid}|{name}|{status}')
except:
    pass
" 2>/dev/null > "$temp_file"
    
    while IFS='|' read -r vmid name status; do
        [[ -z "$vmid" ]] && continue
        config_ip=$(get_config_ip_api "$node" "$vmid" "qemu")
        if [[ -n "$config_ip" ]] && is_private_ip "$config_ip"; then
            printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                "$vmid" "VM" "${name:0:23}" "$status" "$config_ip" "N/A (remote)"
        elif [[ -z "$config_ip" ]]; then
            # Show even without config IP if it's a known VM
            printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                "$vmid" "VM" "${name:0:23}" "$status" "N/A" "N/A (remote)"
        fi
    done < "$temp_file"
    rm -f "$temp_file"
    
    # Process LXC containers
    echo "$lxc_response" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)['data']
    for lxc in sorted(data, key=lambda x: x['vmid']):
        vmid = lxc['vmid']
        name = lxc.get('name', 'N/A')
        status = lxc.get('status', 'unknown')
        print(f'{vmid}|{name}|{status}')
except:
    pass
" 2>/dev/null > "$temp_file"
    
    while IFS='|' read -r vmid name status; do
        [[ -z "$vmid" ]] && continue
        config_ip=$(get_config_ip_api "$node" "$vmid" "lxc")
        if [[ -n "$config_ip" ]] && is_private_ip "$config_ip"; then
            printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                "$vmid" "LXC" "${name:0:23}" "$status" "$config_ip" "N/A (remote)"
        elif [[ -z "$config_ip" ]]; then
            # Show even without config IP if it's a known container
            printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                "$vmid" "LXC" "${name:0:23}" "$status" "N/A" "N/A (remote)"
        fi
    done < "$temp_file"
    rm -f "$temp_file"
    
    echo ""
    echo "Note: Actual IP addresses (runtime) require running on Proxmox host."
    echo "      Config IP shows static IP configuration from Proxmox config files."
}

# Function to list IPs directly (on Proxmox host)
list_ips_direct() {
    echo "Listing private IP address assignments on Proxmox host..."
    echo ""
    
    printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" "VMID" "Type" "Name" "Status" "Config IP" "Actual IP"
    echo "--------------------------------------------------------------------------------"
    
    # List all LXC containers
    if command -v pct >/dev/null 2>&1; then
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            
            local vmid=$(echo "$line" | awk '{print $1}')
            local status=$(echo "$line" | awk '{print $2}')
            
            # Get container name
            local name="N/A"
            local config_file="/etc/pve/lxc/${vmid}.conf"
            if [[ -f "$config_file" ]]; then
                name=$(grep "^hostname:" "$config_file" 2>/dev/null | cut -d' ' -f2 || echo "N/A")
            fi
            
            # Get IPs
            local config_ip=$(get_lxc_config_ip "$vmid")
            local actual_ip=""
            
            if [[ "$status" == "running" ]]; then
                actual_ip=$(get_lxc_actual_ip "$vmid")
            fi
            
            # Only show private IPs
            local display_config_ip=""
            local display_actual_ip=""
            
            if [[ -n "$config_ip" ]] && is_private_ip "$config_ip"; then
                display_config_ip="$config_ip"
            fi
            
            if [[ -n "$actual_ip" ]] && is_private_ip "$actual_ip"; then
                display_actual_ip="$actual_ip"
            fi
            
            # Only print if we have at least one private IP
            if [[ -n "$display_config_ip" ]] || [[ -n "$display_actual_ip" ]]; then
                printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                    "$vmid" "LXC" "${name:0:23}" "$status" \
                    "${display_config_ip:-N/A}" "${display_actual_ip:-N/A}"
            fi
        done < <(pct list 2>/dev/null | tail -n +2)
    fi
    
    # List all VMs
    if command -v qm >/dev/null 2>&1; then
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            
            local vmid=$(echo "$line" | awk '{print $1}')
            local status=$(echo "$line" | awk '{print $2}')
            
            # Get VM name
            local name="N/A"
            local config_file="/etc/pve/qemu-server/${vmid}.conf"
            if [[ -f "$config_file" ]]; then
                name=$(grep "^name:" "$config_file" 2>/dev/null | cut -d' ' -f2 || echo "N/A")
            fi
            
            # Get IPs
            local config_ip=$(get_vm_config_ip "$vmid")
            local actual_ip=""
            
            if [[ "$status" == "running" ]]; then
                actual_ip=$(get_vm_actual_ip "$vmid")
                # Fallback to ARP if guest agent fails
                if [[ -z "$actual_ip" ]]; then
                    actual_ip=$(get_vm_arp_ip "$vmid")
                fi
            fi
            
            # Only show private IPs
            local display_config_ip=""
            local display_actual_ip=""
            
            if [[ -n "$config_ip" ]] && is_private_ip "$config_ip"; then
                display_config_ip="$config_ip"
            fi
            
            if [[ -n "$actual_ip" ]] && is_private_ip "$actual_ip"; then
                display_actual_ip="$actual_ip"
            fi
            
            # Only print if we have at least one private IP
            if [[ -n "$display_config_ip" ]] || [[ -n "$display_actual_ip" ]]; then
                printf "%-7s %-6s %-23s %-10s %-15s %-15s\n" \
                    "$vmid" "VM" "${name:0:23}" "$status" \
                    "${display_config_ip:-N/A}" "${display_actual_ip:-N/A}"
            fi
        done < <(qm list 2>/dev/null | tail -n +2)
    fi
}

# Main execution
if [[ "$ON_PROXMOX_HOST" == "true" ]]; then
    list_ips_direct
else
    # Try API method
    if [[ -n "${PROXMOX_USER:-}" ]] && [[ -n "${PROXMOX_TOKEN_NAME:-}" ]] && [[ -n "${PROXMOX_TOKEN_VALUE:-}" ]]; then
        # Get first node
        nodes_response=$(curl -k -s -m 10 \
            -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \
            "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/nodes" 2>/dev/null)
        
        first_node=$(echo "$nodes_response" | python3 -c "import sys, json; print(json.load(sys.stdin)['data'][0]['node'])" 2>/dev/null)
        
        if [[ -n "$first_node" ]]; then
            list_ips_via_api "$first_node"
        else
            echo "Error: Could not connect to Proxmox API or get node list"
            echo "Please run this script on the Proxmox host for full IP information"
            exit 1
        fi
    else
        echo "Error: Not on Proxmox host and API credentials not configured"
        echo "Please either:"
        echo "  1. Run this script on the Proxmox host, or"
        echo "  2. Configure PROXMOX_USER, PROXMOX_TOKEN_NAME, and PROXMOX_TOKEN_VALUE"
        exit 1
    fi
fi

