#!/usr/bin/env bash
# Rebuild or revert game virtual machines.
#
# Usage:
#   rebuild-vms.sh                          Interactive menu
#   rebuild-vms.sh --vm workstation         Rebuild a single VM (interactive)
#   rebuild-vms.sh --revert                 Revert all VMs to baseline snapshot
#   rebuild-vms.sh --revert --vm workstation
#   rebuild-vms.sh --snapshot --vm workstation --name before-risky-thing
#   rebuild-vms.sh --snapshot --all --name pre-shift-4
#   rebuild-vms.sh --revert --name before-risky-thing --vm workstation
#   rebuild-vms.sh --dry-run [other flags]

set -euo pipefail

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

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

config_read || true

_normalize_dir_path() {
    local path="${1:-}"
    while [[ "$path" == *//* ]]; do
        path="${path//\/\//\/}"
    done
    while [ "$path" != "/" ] && [ "${path%/}" != "$path" ]; do
        path="${path%/}"
    done
    printf '%s\n' "$path"
}

if [ -n "${SC_GAME_DIR:-}" ]; then
    normalized_game_dir="$(_normalize_dir_path "$SC_GAME_DIR")"
    if [ "$normalized_game_dir" != "$SC_GAME_DIR" ]; then
        SC_GAME_DIR="$normalized_game_dir"
        config_write SC_GAME_DIR "$SC_GAME_DIR"
    fi
fi

if [ -n "${SC_IMAGES_DIR:-}" ]; then
    normalized_images_dir="$(_normalize_dir_path "$SC_IMAGES_DIR")"
elif [ -n "${SC_GAME_DIR:-}" ]; then
    normalized_images_dir="$SC_GAME_DIR/images"
else
    normalized_images_dir=""
fi

if [ -n "$normalized_images_dir" ]; then
    if [ "${SC_IMAGES_DIR:-}" != "$normalized_images_dir" ]; then
        SC_IMAGES_DIR="$normalized_images_dir"
        config_write SC_IMAGES_DIR "$SC_IMAGES_DIR"
    fi
    export SC_IMAGE_ROOT="$SC_IMAGES_DIR"
fi

export LIBVIRT_DEFAULT_URI="${SC_LIBVIRT_URI:-${LIBVIRT_DEFAULT_URI:-qemu:///system}}"
export SC_POOL_NAME="${SC_POOL_NAME:-sc-images}"
export SC_NETWORK_NAME="${SC_NETWORK_NAME:-sc-internal}"

# VM display names
declare -A VM_LABEL=(
    [sc-workstation]="workstation"
    [sc-web-server]="web server"
    [sc-build-machine]="build server"
)
declare -A VM_PROFILE=(
    [sc-workstation]=workstation
    [sc-web-server]=web-server
    [sc-build-machine]=build-machine
)
ALL_VMS=(sc-workstation sc-web-server sc-build-machine)

DRY_RUN=false
MODE=""
SINGLE_VM=""
SNAP_NAME=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run)              DRY_RUN=true;      shift ;;
        --revert)               MODE=revert;       shift ;;
        --snapshot)             MODE=snapshot;     shift ;;
        --vm)                   SINGLE_VM="sc-$2"; shift 2 ;;
        --name)                 SNAP_NAME="$2";    shift 2 ;;
        --all)                  SINGLE_VM="";      shift ;;
        *) echo "Unknown argument: $1"; exit 1 ;;
    esac
done

run() {
    if [ "$DRY_RUN" = true ]; then
        echo "  [dry-run] $*"
    else
        "$@"
    fi
}

# Revert one VM to its newest baseline snapshot; prints result.
_revert_to_baseline() {
    local vm="$1"
    local label="${VM_LABEL[$vm]:-$vm}"
    local candidate local_snap=""
    for candidate in "baseline.recovery" "baseline.day-one" "baseline.clean"; do
        if snapshot_exists "$vm" "$candidate" 2>/dev/null; then
            local_snap="$candidate"
            break
        fi
    done
    if [ -n "$local_snap" ]; then
        sc_info "Reverting $label to $local_snap..."
        run snapshot_revert "$vm" "$local_snap"
        sc_ok "$label reverted to $local_snap"
    else
        sc_warn "No baseline snapshot found for $vm — skipping"
    fi
}

_target_vms() {
    if [ -n "$SINGLE_VM" ]; then
        echo "$SINGLE_VM"
    else
        printf '%s\n' "${ALL_VMS[@]}"
    fi
}

# ---------------------------------------------------------------------------
# Non-interactive flag modes
# ---------------------------------------------------------------------------

if [ "$MODE" = "revert" ] && [ -n "$SNAP_NAME" ]; then
    sc_header "REVERTING TO SNAPSHOT: $SNAP_NAME"
    while IFS= read -r vm; do
        label="${VM_LABEL[$vm]:-$vm}"
        sc_info "Reverting $label..."
        if snapshot_exists "$vm" "$SNAP_NAME"; then
            run snapshot_revert "$vm" "$SNAP_NAME"
            sc_ok "$label reverted to $SNAP_NAME"
        else
            sc_warn "Snapshot '$SNAP_NAME' not found on $vm — skipping"
        fi
    done < <(_target_vms)
    exit 0
fi

if [ "$MODE" = "snapshot" ]; then
    [ -n "$SNAP_NAME" ] || { echo "  --snapshot requires --name"; exit 1; }
    while IFS= read -r vm; do
        label="${VM_LABEL[$vm]:-$vm}"
        sc_info "Snapshotting $label as '$SNAP_NAME'..."
        run vm_snapshot_create "$vm" "$SNAP_NAME"
        sc_ok "$label → $SNAP_NAME"
    done < <(_target_vms)
    exit 0
fi

if [ "$MODE" = "revert" ]; then
    sc_header "REVERTING TO BASELINE"
    while IFS= read -r vm; do
        _revert_to_baseline "$vm"
    done < <(_target_vms)
    exit 0
fi

# ---------------------------------------------------------------------------
# Interactive menu
# ---------------------------------------------------------------------------

sc_header "SYSADMIN CHRONICLES — VM TOOLS"

while true; do
    echo "  What would you like to do?"
    echo ""
    echo "  1) Revert all VMs to last known good  (fast — ~30s)"
    echo "  2) Rebuild workstation                (~8 min)"
    echo "  3) Rebuild web server                 (~4 min)"
    echo "  4) Rebuild build server               (~5 min)"
    echo "  5) Rebuild everything                 (~20 min)"
    echo "  6) Take a snapshot"
    echo "  7) Revert to a named snapshot"
    echo ""
    echo "  q) Cancel"
    echo ""
    printf "  > " >/dev/tty
    read -r choice </dev/tty
    echo ""

    case "$choice" in
        q|Q)
            echo "  Cancelled."
            exit 0
            ;;
        1)
            sc_section "Reverting all VMs to baseline"
            for vm in "${ALL_VMS[@]}"; do
                _revert_to_baseline "$vm"
            done
            break
            ;;
        2|3|4|5)
            case "$choice" in
                2) targets=(sc-workstation) ;;
                3) targets=(sc-web-server) ;;
                4) targets=(sc-build-machine) ;;
                5) targets=("${ALL_VMS[@]}") ;;
            esac
            overall_status=0
            for vm in "${targets[@]}"; do
                label="${VM_LABEL[$vm]:-$vm}"
                profile="${VM_PROFILE[$vm]}"
                echo ""
                sc_warn "This will permanently rebuild $label."
                sc_warn "Quest progress on this VM will be lost."
                echo ""
                if sc_confirm "Back up save data first?" "Y"; then
                    BACKUP="$HOME/.local/share/sysadmin-chronicles/saves/pre-rebuild-$(date +%Y%m%d-%H%M%S).json"
                    [ -f "$HOME/.local/share/sysadmin-chronicles/saves/autosave.json" ] \
                        && cp "$HOME/.local/share/sysadmin-chronicles/saves/autosave.json" "$BACKUP" \
                        && sc_ok "Save backed up to $BACKUP" || sc_info "(no autosave found)"
                fi
                if ! sc_confirm "Rebuild $label now?" "N"; then
                    sc_info "Skipping $label."
                    continue
                fi
                sc_section "Rebuilding $label"
                logfile="$HOME/.local/share/sysadmin-chronicles/rebuild-${profile}.log"
                printf "  Rebuilding %-18s " "$label"
                start_ts="$(date +%s)"
                if run vm_rebuild "$profile" $( [ "$DRY_RUN" = true ] && echo "--dry-run" ) \
                        > "$logfile" 2>&1; then
                    elapsed=$(( $(date +%s) - start_ts ))
                    printf "✓  %dm %02ds\n" $(( elapsed / 60 )) $(( elapsed % 60 ))
                else
                    printf "✗\n"
                    sc_warn "Rebuild failed — see $logfile"
                    overall_status=1
                    continue
                fi
                # Re-run quest prep and re-snapshot
                sc_info "Re-running quest prep for $vm..."
                if run bash "$PROJECT_ROOT/tools/setup/seed-vms.sh" --skip-build --vm "${profile//-/_}" \
                    >> "$logfile" 2>&1; then
                    sc_ok "$label rebuild complete"
                else
                    sc_warn "Quest prep had errors — see $logfile"
                    overall_status=1
                fi
            done
            [ "$overall_status" -eq 0 ] || exit "$overall_status"
            break
            ;;
        6)
            echo "  Take a snapshot"
            echo ""
            echo "  Which VM?"
            for i in "${!ALL_VMS[@]}"; do
                vm="${ALL_VMS[$i]}"
                printf "  %d) %s\n" $(( i + 1 )) "${VM_LABEL[$vm]:-$vm}"
            done
            printf "  > " >/dev/tty
            read -r vm_choice </dev/tty
            echo ""
            vm="${ALL_VMS[$(( vm_choice - 1 ))]:-}"
            [ -n "$vm" ] || { sc_warn "Invalid choice"; continue; }
            printf "  Snapshot name (letters, numbers, hyphens): " >/dev/tty
            read -r snap_name </dev/tty
            echo ""
            run vm_snapshot_create "$vm" "$snap_name" \
                && sc_ok "Snapshot created: $snap_name on ${VM_LABEL[$vm]:-$vm}" \
                || sc_warn "Snapshot failed."
            break
            ;;
        7)
            echo "  Revert to a named snapshot"
            echo ""
            echo "  Which VM?"
            for i in "${!ALL_VMS[@]}"; do
                vm="${ALL_VMS[$i]}"
                printf "  %d) %s\n" $(( i + 1 )) "${VM_LABEL[$vm]:-$vm}"
            done
            printf "  > " >/dev/tty
            read -r vm_choice </dev/tty
            echo ""
            vm="${ALL_VMS[$(( vm_choice - 1 ))]:-}"
            [ -n "$vm" ] || { sc_warn "Invalid choice"; continue; }
            echo "  Available snapshots on ${VM_LABEL[$vm]:-$vm}:"
            virsh snapshot-list "$vm" --name 2>/dev/null | grep -v '^$' | sed 's/^/    /' || true
            echo ""
            printf "  Snapshot name to revert to: " >/dev/tty
            read -r snap_name </dev/tty
            echo ""
            snap_date="$(virsh snapshot-info "$vm" "$snap_name" 2>/dev/null | grep 'Creation Time' | awk '{print $3, $4}' || echo "")"
            [ -n "$snap_date" ] && sc_info "Snapshot date: $snap_date"
            if sc_confirm "Revert ${VM_LABEL[$vm]:-$vm} to '$snap_name'?" "N"; then
                run vm_snapshot_revert "$vm" "$snap_name" \
                    && sc_ok "Reverted to $snap_name" \
                    || sc_warn "Revert failed."
            fi
            break
            ;;
        *)
            sc_warn "Invalid choice — enter 1–7 or q."
            ;;
    esac
done

echo ""
