#!/usr/bin/env bash
# Dependency detection and installation for Sysadmin Chronicles.
# Source this file; do not execute directly.

SC_DISTRO=""

detect_distro() {
    if [ -f /etc/arch-release ]; then
        SC_DISTRO=arch
    elif grep -qi ubuntu /etc/os-release 2>/dev/null; then
        SC_DISTRO=ubuntu
    elif [ -f /etc/debian_version ]; then
        SC_DISTRO=debian
    elif [ -f /etc/fedora-release ]; then
        SC_DISTRO=fedora
    elif grep -qi opensuse /etc/os-release 2>/dev/null; then
        SC_DISTRO=opensuse
    else
        SC_DISTRO=unknown
    fi
}

# Per-distro package names for canonical dep names.
# Format: canonical:arch:debian:ubuntu:fedora:opensuse
# Empty field = not applicable / same as above / handled specially.
_SC_DEP_MAP=(
    "libvirt:libvirt:libvirt-daemon-system:libvirt-daemon-system:libvirt:libvirt"
    "qemu-system:qemu-system-x86:qemu-system-x86:qemu-kvm:qemu-kvm:qemu-kvm"
    "qemu-img:qemu-img:qemu-utils:qemu-utils:qemu-img:qemu-tools"
    "virt-install:virt-install:virtinst:virtinst:virt-install:virt-install"
    "virt-viewer:virt-viewer:virt-viewer:virt-viewer:virt-viewer:virt-viewer"
    "cloud-localds:cloud-image-utils:cloud-image-utils:cloud-image-utils:cloud-utils:cloud-utils"
    "genisoimage:cdrtools:genisoimage:genisoimage:genisoimage:genisoimage"
    "xorriso:libisoburn:xorriso:xorriso:xorriso:xorriso"
    "nodejs:nodejs:nodejs:nodejs:nodejs:nodejs"
    "openssh:openssh:openssh-client:openssh-client:openssh-clients:openssh-clients"
)

# Arch-only QEMU SPICE/display extras installed alongside qemu-system
_SC_ARCH_QEMU_EXTRAS=(
    qemu-hw-display-qxl
    qemu-hw-display-virtio-gpu
    qemu-ui-spice-core
    qemu-chardev-spice
    qemu-audio-spice
)

map_package() {
    local dep="$1"
    local distro="${2:-$SC_DISTRO}"
    local entry
    for entry in "${_SC_DEP_MAP[@]}"; do
        IFS=':' read -r name arch debian ubuntu fedora opensuse <<< "$entry"
        if [ "$name" = "$dep" ]; then
            case "$distro" in
                arch)    printf '%s' "$arch" ;;
                debian)  printf '%s' "$debian" ;;
                ubuntu)  printf '%s' "$ubuntu" ;;
                fedora)  printf '%s' "$fedora" ;;
                opensuse) printf '%s' "$opensuse" ;;
            esac
            return
        fi
    done
}

# Outputs canonical dep names that are not yet installed (one per line)
check_deps() {
    local missing=()
    command -v virsh               >/dev/null 2>&1 || missing+=(libvirt)
    command -v qemu-system-x86_64  >/dev/null 2>&1 || missing+=(qemu-system)
    command -v qemu-img            >/dev/null 2>&1 || missing+=(qemu-img)
    command -v virt-install        >/dev/null 2>&1 || missing+=(virt-install)
    command -v remote-viewer       >/dev/null 2>&1 || missing+=(virt-viewer)
    command -v node                >/dev/null 2>&1 || missing+=(nodejs)
    command -v ssh                 >/dev/null 2>&1 || missing+=(openssh)
    # Need at least one cloud-init ISO tool
    if ! command -v cloud-localds >/dev/null 2>&1 \
    && ! command -v genisoimage   >/dev/null 2>&1 \
    && ! command -v mkisofs       >/dev/null 2>&1 \
    && ! command -v xorriso       >/dev/null 2>&1; then
        missing+=(cloud-localds genisoimage xorriso)
    fi
    [ "${#missing[@]}" -gt 0 ] && printf '%s\n' "${missing[@]}" || true
}

# Install a list of canonical dep names. Logs to SC_INSTALL_LOG if set.
install_deps() {
    local deps=("$@")
    local pkgs=()

    for dep in "${deps[@]}"; do
        local pkg
        pkg="$(map_package "$dep")"
        [ -n "$pkg" ] && pkgs+=("$pkg")
    done

    if [ "$SC_DISTRO" = "arch" ]; then
        pkgs+=("${_SC_ARCH_QEMU_EXTRAS[@]}")
    fi

    [ "${#pkgs[@]}" -eq 0 ] && return 0

    local -a pm_cmd
    case "$SC_DISTRO" in
        arch)          pm_cmd=(pacman -S --noconfirm --needed) ;;
        debian|ubuntu) pm_cmd=(apt-get install -y) ;;
        fedora)        pm_cmd=(dnf install -y) ;;
        opensuse)      pm_cmd=(zypper install -y) ;;
        *)
            echo "  Unsupported distro '$SC_DISTRO' — install these manually:"
            printf '    %s\n' "${pkgs[@]}"
            return 1
            ;;
    esac

    sudo "${pm_cmd[@]}" "${pkgs[@]}"

    if [ -n "${SC_INSTALL_LOG:-}" ] && [ "$SC_INSTALL_LOG" != "/dev/null" ]; then
        mkdir -p "$(dirname "$SC_INSTALL_LOG")"
        local distro_label="$SC_DISTRO"
        for pkg in "${pkgs[@]}"; do
            local ver=""
            case "$SC_DISTRO" in
                arch)         ver="$(pacman -Q "$pkg" 2>/dev/null | awk '{print $2}' || true)" ;;
                debian|ubuntu) ver="$(dpkg -l "$pkg" 2>/dev/null | awk '/^ii/{print $3}' | head -1 || true)" ;;
                fedora)       ver="$(rpm -q --queryformat '%{VERSION}' "$pkg" 2>/dev/null || true)" ;;
            esac
            printf '[INSTALLED] %-36s %-14s via %s\n' "$pkg" "${ver:-}" "$distro_label" \
                >> "$SC_INSTALL_LOG"
        done
    fi
}

# Outputs already-installed canonical deps (for log completeness)
log_present_deps() {
    local log_file="${SC_INSTALL_LOG:-}"
    [ -z "$log_file" ] || [ "$log_file" = "/dev/null" ] && return
    local distro_label="$SC_DISTRO"
    for dep in libvirt qemu-system qemu-img virt-install virt-viewer nodejs openssh; do
        local bin
        case "$dep" in
            libvirt)      bin=virsh ;;
            qemu-system)  bin=qemu-system-x86_64 ;;
            qemu-img)     bin=qemu-img ;;
            virt-install) bin=virt-install ;;
            virt-viewer)  bin=remote-viewer ;;
            nodejs)       bin=node ;;
            openssh)      bin=ssh ;;
        esac
        if command -v "$bin" >/dev/null 2>&1; then
            printf '[SKIPPED]   %-36s already installed\n' "$dep" >> "$log_file"
        fi
    done
}

dep_label() {
    case "$1" in
        libvirt)                         echo "Virtual machine manager (libvirt)" ;;
        qemu-system)                     echo "KVM virtualization support (QEMU)" ;;
        qemu-img)                        echo "VM disk image tools (qemu-img)" ;;
        virt-install)                    echo "VM installer (virt-install)" ;;
        virt-viewer)                     echo "SPICE display viewer (virt-viewer)" ;;
        cloud-localds|genisoimage|xorriso) echo "Cloud image tools" ;;
        nodejs)                          echo "Node.js runtime" ;;
        openssh)                         echo "SSH client" ;;
        *)                               echo "$1" ;;
    esac
}
