#!/usr/bin/env bash
# Sysadmin Chronicles — Installer
# Usage: bash install.sh

set -euo pipefail

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

source "$PROJECT_ROOT/tools/lib/ui.sh"
source "$PROJECT_ROOT/tools/lib/config.sh"
source "$PROJECT_ROOT/tools/lib/deps.sh"
source "$PROJECT_ROOT/tools/lib/libvirt.sh"
source "$PROJECT_ROOT/tools/lib/vm.sh"

OWNER_USER="${SUDO_USER:-$USER}"
OWNER_HOME="$(getent passwd "$OWNER_USER" | cut -d: -f6)"
OWNER_HOME="${OWNER_HOME:-$HOME}"

SC_LOG_DIR="$OWNER_HOME/.local/share/sysadmin-chronicles"
export SC_INSTALL_LOG="$SC_LOG_DIR/install.log"
export LIBVIRT_DEFAULT_URI="${LIBVIRT_DEFAULT_URI:-qemu:///system}"

# ---------------------------------------------------------------------------
# Phase 1 — Welcome
# ---------------------------------------------------------------------------

sc_header "SYSADMIN CHRONICLES — SETUP"
cat << 'WELCOME'
Welcome! This installer will:
  • Install a few system tools (KVM, QEMU, libvirt)
  • Set up a private virtual network for the game
  • Build three virtual machines (~30 minutes, once only)

WELCOME

DEFAULT_GAME_DIR="$OWNER_HOME/Games/sysadmin-chronicles"
[ "$PROJECT_ROOT" = "$DEFAULT_GAME_DIR" ] || DEFAULT_GAME_DIR="$PROJECT_ROOT"

SC_GAME_DIR="$(sc_prompt "Where would you like to install the game?" "$DEFAULT_GAME_DIR")"
while [[ "$SC_GAME_DIR" == *//* ]]; do
    SC_GAME_DIR="${SC_GAME_DIR//\/\//\/}"
done
while [ "$SC_GAME_DIR" != "/" ] && [ "${SC_GAME_DIR%/}" != "$SC_GAME_DIR" ]; do
    SC_GAME_DIR="${SC_GAME_DIR%/}"
done
echo ""
SC_IMAGES_DIR="$SC_GAME_DIR/images"

# Build scripts normally default to /var/lib/libvirt when using qemu:///system.
# The installer asks for a custom game directory, so force the VM tooling to use
# the libvirt storage pool path selected above instead of silently falling back
# to /var/lib/libvirt/images/sysadmin-chronicles.
export SC_HOME="$SC_LOG_DIR"
export SC_IMAGE_ROOT="$SC_IMAGES_DIR"
export SC_POOL_NAME="sc-images"
export SC_NETWORK_NAME="sc-internal"
export SC_OWNER_USER="$OWNER_USER"
export SC_OWNER_HOME="$OWNER_HOME"

sc_log_append() {
    mkdir -p "$SC_LOG_DIR"
    {
        printf '\n[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
    } >> "$SC_INSTALL_LOG" 2>/dev/null || true
}

sc_log_cmd() {
    mkdir -p "$SC_LOG_DIR"
    {
        printf '\n[%s] $' "$(date '+%Y-%m-%d %H:%M:%S')"
        printf ' %q' "$@"
        printf '\n'
        "$@"
    } >> "$SC_INSTALL_LOG" 2>&1
}


# ---------------------------------------------------------------------------
# Phase 2 — Silent system check
# ---------------------------------------------------------------------------

detect_distro

if [ "$SC_DISTRO" = "unknown" ]; then
    sc_warn "Could not detect your Linux distribution."
    sc_warn "Dependency auto-install may not work — you may need to install packages manually."
    echo ""
fi

mapfile -t _missing_deps < <(check_deps 2>/dev/null || true)

# ---------------------------------------------------------------------------
# Phase 3 — Dependency install (only if needed)
# ---------------------------------------------------------------------------

if [ "${#_missing_deps[@]}" -gt 0 ]; then
    sc_section "System check"
    echo ""
    echo "  Your system is missing the following tools:"
    echo ""
    _shown_labels=""
    for _dep in "${_missing_deps[@]}"; do
        [ -z "$_dep" ] && continue
        _label="$(dep_label "$_dep")"
        [ -z "$_label" ] && continue
        case "|${_shown_labels}|" in
            *"|${_label}|"*) ;;
            *) echo "    • $_label"; _shown_labels="${_shown_labels}|${_label}" ;;
        esac
    done
    echo ""
    if sc_confirm "Install them now? You'll be asked for your password." "Y"; then
        echo ""
        mkdir -p "$SC_LOG_DIR"
        # Write log header
        cat > "$SC_INSTALL_LOG" << EOF
# Sysadmin Chronicles — Install Log
# Created: $(date '+%Y-%m-%d %H:%M:%S')
# Distro:  ${SC_DISTRO} ($(uname -r))
# Game dir: $SC_GAME_DIR
# Images:   $SC_IMAGES_DIR

EOF
        install_deps "${_missing_deps[@]}"
        log_present_deps
        echo ""
        # Append manual removal hint
        {
            echo ""
            echo "# To remove manually:"
            printf '# sudo %s\n' "$(case "$SC_DISTRO" in
                arch) echo 'pacman -Rns libvirt qemu-system-x86 virt-install virt-viewer' ;;
                debian|ubuntu) echo 'apt-get remove libvirt-daemon-system qemu-kvm virt-manager' ;;
                fedora) echo 'dnf remove libvirt qemu-kvm virt-install' ;;
                *) echo 'remove the packages listed above' ;;
            esac)"
        } >> "$SC_INSTALL_LOG"
        sc_ok "Dependencies installed."
        echo ""
        echo "  Install log: $SC_INSTALL_LOG"
        echo ""
    else
        echo ""
        sc_warn "Skipping dependency install. Some features may not work."
        echo ""
    fi
else
    mkdir -p "$SC_LOG_DIR"
    if [ ! -f "$SC_INSTALL_LOG" ]; then
        cat > "$SC_INSTALL_LOG" << EOF
# Sysadmin Chronicles — Install Log
# Created: $(date '+%Y-%m-%d %H:%M:%S')
# Distro:  ${SC_DISTRO} ($(uname -r))
# Game dir: $SC_GAME_DIR
# Images:   $SC_IMAGES_DIR

EOF
        log_present_deps
    fi
fi

# ---------------------------------------------------------------------------
# Phase 4 — Network, storage, and SSH key setup
# ---------------------------------------------------------------------------

# Ensure libvirtd is running before touching networks or pools.
# Pacman installs the socket unit but does not start/enable it.
_libvirtd_ready=false
_need_relogin=false

# Ensure user is in the libvirt group (needed for virsh access without sudo)
if ! groups "$OWNER_USER" 2>/dev/null | grep -qw libvirt; then
    sc_info "Adding $OWNER_USER to the libvirt group..."
    sudo usermod -aG libvirt "$OWNER_USER" 2>/dev/null || true
    _need_relogin=true
fi

# Clear any failed unit state from a previous attempt
sudo systemctl reset-failed libvirtd.service libvirtd.socket 2>/dev/null || true

if ! systemctl is-active --quiet libvirtd.service 2>/dev/null; then
    sc_info "Starting virtual machine daemon..."
    # Enable the socket for future boots, start the service directly now
    sudo systemctl enable libvirtd.socket >/dev/null 2>&1 || true
    if ! sudo systemctl start libvirtd.service >/dev/null 2>&1; then
        echo ""
        echo "  libvirtd failed to start.  Details:"
        sudo systemctl status libvirtd.service --no-pager -l 2>&1 | tail -25 | sed 's/^/    /'
        echo ""
        sc_fail "Fix the error above, then run install.sh again."
    fi
fi

# Wait up to 30s for libvirtd.service to reach active state (pure systemd
# check — no virsh connection needed, works regardless of group membership
# in the current session).
for _i in $(seq 1 60); do
    if systemctl is-active --quiet libvirtd.service 2>/dev/null; then
        _libvirtd_ready=true
        break
    fi
    sleep 0.5
done

if [ "$_libvirtd_ready" != true ]; then
    echo ""
    echo "  libvirtd did not reach active state.  Current status:"
    sudo systemctl status libvirtd.service --no-pager -l 2>&1 | tail -25 | sed 's/^/    /'
    echo ""
    sc_fail "Fix the error above, then run install.sh again."
fi

# If the group was just added, the current shell does not have it yet. The
# install can still proceed by using sudo for virsh operations.
if virsh -c "$LIBVIRT_DEFAULT_URI" list >/dev/null 2>&1; then
    export SC_VIRSH_SUDO=false
else
    export SC_VIRSH_SUDO=true
    sc_log_append "virsh is not usable by $OWNER_USER in this session; using sudo for installer libvirt operations."
fi

sc_log_append "Installer paths: SC_GAME_DIR=$SC_GAME_DIR SC_IMAGES_DIR=$SC_IMAGES_DIR SC_IMAGE_ROOT=$SC_IMAGE_ROOT LIBVIRT_DEFAULT_URI=$LIBVIRT_DEFAULT_URI SC_VIRSH_SUDO=${SC_VIRSH_SUDO:-false}"
sc_log_cmd id || true
sc_log_cmd groups "$OWNER_USER" || true
sc_log_cmd systemctl is-active libvirtd.service || true

sc_section "Setting up game network"
echo ""

NETWORK_XML="$PROJECT_ROOT/tools/vm/network-sc-internal.xml"

sc_spinner "Creating private game network"
if ! ensure_network "sc-internal" "$NETWORK_XML"; then
    sc_spinner_stop
    echo ""
    sc_fail "Could not create the game network.

    Make sure the virtual machine tools are installed and running:
      sudo systemctl enable --now libvirtd.socket

    Then run install.sh again."
fi
sc_spinner_stop
sc_ok "Private game network created"

sc_spinner "Configuring VM image storage"
if ! ensure_pool "sc-images" "$SC_IMAGES_DIR"; then
    sc_spinner_stop
    sc_fail "Could not configure image storage at $SC_IMAGES_DIR"
fi
sc_spinner_stop
sc_ok "VM image storage configured at $SC_IMAGES_DIR"

# Pre-create subdirectories used by tools/vm/lib/common.sh. Since these live
# under the user-selected install path, they should be user-writable. This also
# fails early with a useful message instead of producing a one-line build log.
if ! mkdir -p "$SC_IMAGES_DIR/base" "$SC_IMAGES_DIR/seed"; then
    sc_fail "Could not create VM image directories under $SC_IMAGES_DIR"
fi
chown -R "$OWNER_USER:$OWNER_USER" "$SC_IMAGES_DIR" 2>/dev/null || true
sc_log_cmd ls -lah "$SC_IMAGES_DIR" || true

SC_SSH_KEY="$OWNER_HOME/.ssh/sc_host_key"
if [ ! -f "$SC_SSH_KEY" ]; then
    sc_spinner "Generating game access keys"
    mkdir -p "$(dirname "$SC_SSH_KEY")"
    ssh-keygen -t ed25519 -N "" -C "sysadmin-chronicles-host" -f "$SC_SSH_KEY" >/dev/null 2>&1
    chmod 600 "$SC_SSH_KEY"
    chmod 644 "${SC_SSH_KEY}.pub"
    chown "$OWNER_USER:$OWNER_USER" "$SC_SSH_KEY" "${SC_SSH_KEY}.pub" 2>/dev/null || true
    sc_spinner_stop
    sc_ok "Game access keys generated"
else
    sc_ok "Game access keys already present"
fi

# Write config (survives game dir moves)
config_write SC_GAME_DIR   "$SC_GAME_DIR"
config_write SC_IMAGES_DIR "$SC_IMAGES_DIR"
config_write SC_LIBVIRT_URI "$LIBVIRT_DEFAULT_URI"
config_write SC_INSTALL_DATE "$(date '+%Y-%m-%d')"
echo ""

# ---------------------------------------------------------------------------
# Phase 5 — VM build
# ---------------------------------------------------------------------------

sc_section "Building your game world"
echo ""
echo "  This happens once and takes about 30 minutes."
echo "  You can leave this running in the background."
echo ""

_build_vm() {
    local label="$1"
    local n="$2"
    local total="$3"
    local profile="$4"
    local logfile="$SC_LOG_DIR/build-${profile}.log"
    local start_ts elapsed mins secs
    start_ts="$(date +%s)"
    printf "  Building %-20s (%d/%d) " "$label" "$n" "$total"
    {
        echo "# Sysadmin Chronicles VM build log"
        echo "# Created: $(date '+%Y-%m-%d %H:%M:%S')"
        echo "# Profile: $profile"
        echo "# Game dir: $SC_GAME_DIR"
        echo "# Images: $SC_IMAGES_DIR"
        echo "# SC_IMAGE_ROOT: $SC_IMAGE_ROOT"
        echo "# LIBVIRT_DEFAULT_URI: $LIBVIRT_DEFAULT_URI"
        echo "# SC_VIRSH_SUDO: ${SC_VIRSH_SUDO:-false}"
        echo ""
    } > "$logfile"
    if vm_build "$profile" >> "$logfile" 2>&1; then
        elapsed=$(( $(date +%s) - start_ts ))
        mins=$(( elapsed / 60 ))
        secs=$(( elapsed % 60 ))
        printf "✓  %dm %02ds\n" "$mins" "$secs"
    else
        printf "✗\n"
        sc_warn "Build failed — see $logfile"
        return 1
    fi
}

echo "Generating TLS certificates..."
bash "$PROJECT_ROOT/tools/setup/generate-certs.sh"
echo ""

_build_vm "workstation"  1 3 "workstation"
_build_vm "web server"   2 3 "web-server"
_build_vm "build server" 3 3 "build-machine"

printf "  Setting up quest scenarios          "
bash "$PROJECT_ROOT/tools/setup/seed-vms.sh" --skip-build \
    > "$SC_LOG_DIR/seed-vms.log" 2>&1 && printf "✓\n" || { printf "✗\n"; sc_warn "Quest setup had errors — see $SC_LOG_DIR/seed-vms.log"; }
echo ""

# ---------------------------------------------------------------------------
# Phase 6 — Application menu entry
# ---------------------------------------------------------------------------

sc_section "Application menu launcher"
echo ""
if sc_confirm "Create an application-menu launcher? This does not add a desktop icon." "Y"; then
    DESKTOP_FILE="$OWNER_HOME/.local/share/applications/sysadmin-chronicles.desktop"
    mkdir -p "$(dirname "$DESKTOP_FILE")"
    cat > "$DESKTOP_FILE" << EOF
[Desktop Entry]
Name=Sysadmin Chronicles
Comment=A sysadmin simulation game
Exec=bash $SC_GAME_DIR/start-game.sh
Terminal=true
Type=Application
Categories=Game;
EOF
    sc_ok "Application-menu launcher created"
fi
echo ""

# ---------------------------------------------------------------------------
# Phase 7 — Done
# ---------------------------------------------------------------------------

sc_done_banner
cat << EOF
  Start the game:
    bash $SC_GAME_DIR/start-game.sh
    (or from your system application menu if you created the launcher; no desktop icon is installed)

  Rebuild the virtual machines at any time:
    bash $SC_GAME_DIR/tools/vm/rebuild-vms.sh

  Install log:
    $SC_INSTALL_LOG

EOF

if [ "$_need_relogin" = true ]; then
    sc_warn "You were added to the 'libvirt' group during install."
    sc_warn "Log out and back in before running the game, or run:"
    echo "    newgrp libvirt"
    echo ""
fi
