#!/bin/bash
# Template Validation Script
# Comprehensive testing of created templates

set -euo pipefail

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_pass() {
    echo -e "${GREEN}✓${NC} $1"
}

log_fail() {
    echo -e "${RED}✗${NC} $1"
}

log_info() {
    echo -e "${YELLOW}ℹ${NC} $1"
}

#=============================================================================
# Software Validation Functions
#=============================================================================

# Check if a command exists on the VM
check_command_exists() {
    local vm_id=$1
    local command=$2
    local description=${3:-$command}

    if qm guest exec "$vm_id" -- which "$command" &>/dev/null || \
       qm guest exec "$vm_id" -- command -v "$command" &>/dev/null; then
        log_pass "$description found"
        return 0
    else
        log_fail "$description not found"
        return 1
    fi
}

# Check if a service is running on the VM
check_service_running() {
    local vm_id=$1
    local service=$2
    local description=${3:-$service}

    if qm guest exec "$vm_id" -- systemctl is-active "$service" &>/dev/null; then
        log_pass "$description service is active"
        return 0
    else
        log_fail "$description service is not active"
        return 1
    fi
}

# Get command version
get_command_version() {
    local vm_id=$1
    local command=$2
    local version_flag=${3:---version}

    # Try to get version, suppress errors
    local version
    version=$(qm guest exec "$vm_id" -- "$command" "$version_flag" 2>/dev/null | head -1 | grep -oP '\d+\.\d+(\.\d+)?' | head -1)
    echo "$version"
}

# Detect OS family for package manager commands
detect_os_family() {
    local vm_id=$1

    # Try to detect OS from os-release
    if qm guest exec "$vm_id" -- test -f /etc/os-release &>/dev/null; then
        local os_id
        os_id=$(qm guest exec "$vm_id" -- grep -oP '^ID=\K.*' /etc/os-release 2>/dev/null | tr -d '"')

        case "$os_id" in
            ubuntu|debian)
                echo "debian"
                ;;
            rocky|almalinux|rhel|centos|fedora)
                echo "rhel"
                ;;
            opensuse*|sles)
                echo "suse"
                ;;
            *)
                echo "unknown"
                ;;
        esac
    else
        echo "unknown"
    fi
}

# Validate base profile packages
validate_base_profile() {
    local vm_id=$1
    local os_family=$2

    echo
    echo "   Base Profile Validation:"
    echo "   ------------------------"

    local failed=0

    # Essential tools
    check_command_exists "$vm_id" "curl" "curl" || ((failed++))
    check_command_exists "$vm_id" "wget" "wget" || ((failed++))

    # Editor (vim or nano)
    if ! check_command_exists "$vm_id" "vim" "vim"; then
        check_command_exists "$vm_id" "nano" "nano (fallback editor)" || ((failed++))
    fi

    # SSH server
    check_service_running "$vm_id" "sshd" "SSH server" || check_service_running "$vm_id" "ssh" "SSH server" || ((failed++))

    return $failed
}

# Validate extended profile packages
validate_extended_profile() {
    local vm_id=$1
    local os_family=$2

    echo
    echo "   Extended Profile Validation:"
    echo "   ---------------------------"

    local failed=0

    # Version Control
    if check_command_exists "$vm_id" "git" "git"; then
        local git_version
        git_version=$(get_command_version "$vm_id" "git")
        [[ -n "$git_version" ]] && echo "      version: $git_version"
    else
        ((failed++))
    fi

    # Note: Docker validation removed - Docker is now installed via Ansible playbook
    # See ansible/playbooks/docker-compose.yml for Docker installation

    # DevOps Tools
    if check_command_exists "$vm_id" "terraform" "terraform"; then
        local tf_version
        tf_version=$(get_command_version "$vm_id" "terraform")
        [[ -n "$tf_version" ]] && echo "      version: $tf_version"
    else
        ((failed++))
    fi

    if check_command_exists "$vm_id" "packer" "packer"; then
        local packer_version
        packer_version=$(get_command_version "$vm_id" "packer")
        [[ -n "$packer_version" ]] && echo "      version: $packer_version"
    else
        ((failed++))
    fi

    check_command_exists "$vm_id" "ansible" "ansible" || ((failed++))

    # Kubernetes Tools
    if check_command_exists "$vm_id" "kubectl" "kubectl"; then
        local kubectl_version
        kubectl_version=$(get_command_version "$vm_id" "kubectl" "--client")
        [[ -n "$kubectl_version" ]] && echo "      version: $kubectl_version"
    else
        ((failed++))
    fi

    if check_command_exists "$vm_id" "helm" "helm"; then
        local helm_version
        helm_version=$(get_command_version "$vm_id" "helm")
        [[ -n "$helm_version" ]] && echo "      version: $helm_version"
    else
        ((failed++))
    fi

    if check_command_exists "$vm_id" "k9s" "k9s"; then
        local k9s_version
        k9s_version=$(get_command_version "$vm_id" "k9s")
        [[ -n "$k9s_version" ]] && echo "      version: $k9s_version"
    else
        ((failed++))
    fi

    # Cloud CLIs
    if check_command_exists "$vm_id" "aws" "aws cli"; then
        local aws_version
        aws_version=$(get_command_version "$vm_id" "aws")
        [[ -n "$aws_version" ]] && echo "      version: $aws_version"
    else
        ((failed++))
    fi

    # Azure CLI (may not be on Rocky/RHEL)
    if [[ "$os_family" != "rhel" ]] || qm guest exec "$vm_id" -- which az &>/dev/null; then
        check_command_exists "$vm_id" "az" "azure cli" || ((failed++))
    fi

    # Monitoring Tools
    check_command_exists "$vm_id" "htop" "htop" || ((failed++))

    return $failed
}

# Test VM from template
test_template() {
    local template_id=$1
    local test_vm_id=$((template_id + 10000))

    echo "========================================"
    echo "Template Validation"
    echo "========================================"
    echo "Template ID: $template_id"
    echo "Test VM ID:  $test_vm_id"
    echo

    # Check if template exists
    echo "1. Checking template exists..."
    if ! qm status "$template_id" &>/dev/null; then
        log_fail "Template $template_id does not exist"
        return 1
    fi
    log_pass "Template $template_id found"

    # Check if it's actually a template
    local is_template
    is_template=$(qm config "$template_id" | grep "^template:" | awk '{print $2}')
    if [[ "$is_template" != "1" ]]; then
        log_fail "VM $template_id is not a template"
        return 1
    fi
    log_pass "VM $template_id is a template"

    echo
    echo "2. Creating test VM from template..."
    if qm status "$test_vm_id" &>/dev/null; then
        log_info "Test VM $test_vm_id already exists, removing..."
        qm stop "$test_vm_id" || true
        qm destroy "$test_vm_id" || true
        sleep 2
    fi

    # Get template name for test VM naming
    local template_name
    template_name=$(qm config "$template_id" | grep "^name:" | awk '{print $2}')
    local test_vm_name="${template_name}-test"

    # Create linked clone (faster and uses less space)
    qm clone "$template_id" "$test_vm_id" --name "$test_vm_name"
    log_pass "Test VM created (linked clone)"

    echo
    echo "3. Starting test VM..."
    qm start "$test_vm_id"
    log_pass "VM started"

    # Wait for boot
    echo
    echo "4. Waiting for QEMU guest agent (max 180s)..."
    echo "   This may take a while for first boot (OS initialization, cloud-init, swap activation)..."

    # Disable errexit for this section to prevent premature exit
    set +e

    local attempts=0
    local max_attempts=60  # 60 * 3 seconds = 180 seconds
    local agent_ready=0

    while [[ $attempts -le $max_attempts ]]; do
        # Try to ping the agent
        if qm agent "$test_vm_id" ping &>/dev/null; then
            agent_ready=1
            break
        fi

        # Progress indicator
        local elapsed=$((attempts * 3))
        if (( attempts % 10 == 0 )) && (( attempts > 0 )); then
            echo -n " [${elapsed}s]"
        else
            echo -n "."
        fi

        sleep 3
        attempts=$((attempts + 1))
    done
    echo

    # Re-enable errexit
    set -e

    # Check if agent responded
    if [[ $agent_ready -eq 1 ]]; then
        local elapsed=$((attempts * 3))
        log_pass "QEMU guest agent is responding (after ${elapsed} seconds)"
    else
        log_fail "QEMU guest agent not responding after 180 seconds"
        log_info "VM may still be booting - check manually: qm agent $test_vm_id ping"
        cleanup_test_vm "$test_vm_id"
        return 1
    fi

    # Test cloud-init
    echo
    echo "5. Checking cloud-init..."
    if qm guest exec "$test_vm_id" -- test -f /var/lib/cloud/instance/boot-finished 2>/dev/null; then
        log_pass "cloud-init boot finished"
    else
        log_fail "cloud-init did not complete"
    fi

    # Check cloud-init network is disabled
    echo
    echo "6. Checking cloud-init network configuration..."
    if qm guest exec "$test_vm_id" -- test -f /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg 2>/dev/null; then
        log_pass "cloud-init network disable config exists"
    else
        log_fail "cloud-init network disable config MISSING"
    fi

    # Test QEMU agent
    echo
    echo "7. Testing QEMU guest agent..."
    if qm agent "$test_vm_id" get-osinfo >/dev/null 2>&1; then
        log_pass "QEMU agent functional"
    else
        log_fail "QEMU agent not working"
    fi

    # Test network
    echo
    echo "8. Testing network connectivity..."
    if qm guest exec "$test_vm_id" -- ping -c 3 -W 5 8.8.8.8 >/dev/null 2>&1; then
        log_pass "Network connectivity working"
    else
        log_fail "No network connectivity"
    fi

    # Software validation
    echo
    echo "9. Validating installed software..."

    # Detect OS family
    local os_family
    os_family=$(detect_os_family "$test_vm_id")
    log_info "Detected OS family: $os_family"

    # Detect package profile from template name
    local template_name
    template_name=$(qm config "$template_id" | grep "^name:" | awk '{print $2}')

    local package_profile="minimal"
    if [[ "$template_name" =~ extended ]]; then
        package_profile="extended"
    elif [[ "$template_name" =~ base ]]; then
        package_profile="base"
    fi

    log_info "Package profile: $package_profile"

    # Run appropriate validation based on profile
    local software_failed=0
    case "$package_profile" in
        minimal)
            log_info "Minimal profile - skipping software validation"
            ;;
        base)
            validate_base_profile "$test_vm_id" "$os_family" || software_failed=$?
            ;;
        extended)
            validate_base_profile "$test_vm_id" "$os_family" || software_failed=$?
            validate_extended_profile "$test_vm_id" "$os_family" || ((software_failed+=$?))
            ;;
    esac

    if [[ $software_failed -eq 0 ]]; then
        echo
        log_pass "Software validation complete - all packages found"
    else
        echo
        log_fail "Software validation failed - $software_failed package(s) missing"
    fi

    # Run full network tests
    echo
    echo "10. Running comprehensive network tests..."
    if ./tests/test-network-config.sh "$test_vm_id"; then
        log_pass "Network configuration tests passed"
    else
        log_fail "Network configuration tests failed"
    fi

    # Cleanup
    echo
    echo "11. Cleanup..."
    cleanup_test_vm "$test_vm_id"

    echo
    echo "========================================"
    log_pass "All tests passed!"
    echo "========================================"
    echo
    log_info "Press any key to continue..."
    read -n 1 -s -r </dev/tty

    return 0
}

cleanup_test_vm() {
    local vm_id=$1

    # Redirect input from tty to ensure prompt works even when called from dialog
    read -p "Remove test VM $vm_id? (Y/n): " -n 1 -r </dev/tty
    echo
    if [[ ! $REPLY =~ ^[Nn]$ ]]; then
        qm stop "$vm_id" || true
        qm destroy "$vm_id" || true
        log_info "Test VM removed"
    else
        log_info "Test VM kept for manual inspection (ID: $vm_id)"
    fi
}

# Usage
usage() {
    cat <<EOF
Usage: $0 TEMPLATE_ID

Tests a Proxmox VM template by creating a test VM and validating functionality.

Tests performed:
  - Template exists and is valid
  - Test VM creation from template
  - QEMU guest agent functionality
  - Cloud-init completion
  - Cloud-init network disabled
  - Network connectivity
  - Installed software validation (profile-based)
  - Comprehensive network configuration

Arguments:
  TEMPLATE_ID    Proxmox template ID to test

Example:
  $0 9000

EOF
}

# Main
main() {
    if [[ $# -lt 1 ]]; then
        usage
        exit 1
    fi

    local template_id=$1

    test_template "$template_id"
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
