#!/usr/bin/env bash
# seed-vms.sh — Build all game VMs and create baseline snapshots.
#
# This script orchestrates the full VM provisioning pipeline:
#   1. Build base VM images (cloud-init or manual install)
#   2. Install guest helper binaries
#   3. Run quest-prep scripts for each Tier 1 quest
#   4. Take named baseline snapshots
#
# Prerequisites: Run first-run-setup.sh first (creates networks + pool).
#
# Usage:
#   bash tools/setup/seed-vms.sh                   # Build all VMs
#   bash tools/setup/seed-vms.sh --dry-run          # Preview only
#   bash tools/setup/seed-vms.sh --vm workstation   # One VM only
#   bash tools/setup/seed-vms.sh --skip-build       # Prep scripts + snapshots only
#
# AGENT RULES:
#   - Never run quest-prep scripts against live player VMs.
#   - All prep scripts must be idempotent (safe to run twice).
#   - Snapshots are only taken after prep scripts complete successfully.

set -euo pipefail

OWNER_USER="${SUDO_USER:-$USER}"
OWNER_HOME="$(getent passwd "$OWNER_USER" | cut -d: -f6)"
OWNER_HOME="${OWNER_HOME:-$HOME}"
export LIBVIRT_DEFAULT_URI="${LIBVIRT_DEFAULT_URI:-qemu:///system}"
export SC_OWNER_USER="$OWNER_USER"
export SC_OWNER_HOME="$OWNER_HOME"
export SC_SSH_KEY="${SC_SSH_KEY:-$OWNER_HOME/.ssh/sc_host_key}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
VM_TOOLS="$PROJECT_ROOT/tools/vm"
QUEST_PREP="$VM_TOOLS/quest-prep"

source "$PROJECT_ROOT/tools/lib/config.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_IMAGES_DIR:-}" ]; then
    SC_IMAGES_DIR="$(normalize_dir_path "$SC_IMAGES_DIR")"
    export SC_IMAGE_ROOT="$SC_IMAGES_DIR"
fi
export SC_POOL_NAME="${SC_POOL_NAME:-sc-images}"
export SC_NETWORK_NAME="${SC_NETWORK_NAME:-sc-internal}"

DRY_RUN=false
SKIP_BUILD=false
SINGLE_VM=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run)    DRY_RUN=true;        shift ;;
        --skip-build) SKIP_BUILD=true;     shift ;;
        --vm)         SINGLE_VM="$2";      shift 2 ;;
        *) echo "Unknown argument: $1"; exit 1 ;;
    esac
done

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

step() { echo ""; echo "── $* ───────────────────────────────────────"; }
ok()   { echo "  ✓ $*"; }
info() { echo "  → $*"; }
fail() { echo "  ✗ $*"; exit 1; }
vm_selected() {
    local key="$1"
    [ -z "$SINGLE_VM" ] || [ "$SINGLE_VM" = "$key" ]
}
domain_selected() {
    local domain="$1"
    case "$domain" in
        sc-workstation) vm_selected "workstation" ;;
        sc-web-server) vm_selected "web_server" ;;
        sc-build-machine) vm_selected "build_machine" ;;
        *) return 1 ;;
    esac
}
require_file() {
    local path="$1"
    local label="$2"
    if [ ! -f "$path" ]; then
        fail "$label is missing: $path"
    fi
}

echo ""
echo "══════════════════════════════════════════════════"
echo "  Sysadmin Chronicles — VM Seed Pipeline"
echo "══════════════════════════════════════════════════"
[ "$DRY_RUN" = "true" ] && echo "  [DRY-RUN mode]"
echo ""

step "Validating provisioning toolchain"
require_file "$QUEST_PREP/Q001-prep.sh" "Q001 prep script"
require_file "$QUEST_PREP/Q002-prep.sh" "Q002 prep script"
require_file "$QUEST_PREP/Q003-prep.sh" "Q003 prep script"
require_file "$QUEST_PREP/Q004-prep.sh" "Q004 prep script"
require_file "$QUEST_PREP/Q006-prep.sh" "Q006 prep script"
require_file "$QUEST_PREP/Q006-post-clean.sh" "Q006 post-clean script"

if [ "$SKIP_BUILD" = "false" ]; then
    missing_scripts=()
    for script in \
        "$VM_TOOLS/build-workstation.sh" \
        "$VM_TOOLS/build-web-server.sh" \
        "$VM_TOOLS/build-build-machine.sh" \
        "$VM_TOOLS/install-guest-helper.sh" \
        "$VM_TOOLS/suppress-maintenance-noise.sh"
    do
        if [ ! -f "$script" ]; then
            missing_scripts+=("$script")
        fi
    done

    if [ "${#missing_scripts[@]}" -gt 0 ]; then
        echo "  ✗ VM provisioning pipeline is incomplete in this repo checkout."
        echo "    Missing files:"
        for script in "${missing_scripts[@]}"; do
            echo "      - $script"
        done
        echo ""
        echo "    Current state:"
        echo "      - The Godot game and authored content are present."
        echo "      - The VM image build/provision helper scripts are not."
        echo ""
        echo "    Real VM seeding cannot complete until those scripts are added."
        exit 1
    fi
fi

# ---------------------------------------------------------------------------
# STEP 1 — Build base images
# ---------------------------------------------------------------------------

if [ "$SKIP_BUILD" = "false" ]; then
    step "Building VM base images"
    info "NOTE: VM image builds require cloud-init ISO or manual install."
    info "      See docs/ARCHITECTURE.md §5.3.1 for workstation profile guidance."
    info "      See tools/vm/build-*.sh scripts for per-VM build details."
    echo ""

    if vm_selected "workstation"; then
        info "Building workstation (ares) — Debian XFCE desktop..."
        run bash "$VM_TOOLS/build-workstation.sh" $([ "$DRY_RUN" = "true" ] && echo "--dry-run")
    fi

    if vm_selected "web_server"; then
        info "Building web_server (hermes) — headless Debian..."
        run bash "$VM_TOOLS/build-web-server.sh" $([ "$DRY_RUN" = "true" ] && echo "--dry-run")
    fi

    if vm_selected "build_machine"; then
        info "Building build_machine (vulcan) — headless Arch..."
        run bash "$VM_TOOLS/build-build-machine.sh" $([ "$DRY_RUN" = "true" ] && echo "--dry-run")
    fi
fi

# ---------------------------------------------------------------------------
# STEP 1b — Verify baseline connectivity
# ---------------------------------------------------------------------------

if [ "$SKIP_BUILD" = "false" ] && [ "$DRY_RUN" = "false" ]; then
    step "Verifying baseline connectivity"
    for dom_host in "sc-web-server:hermes" "sc-build-machine:vulcan"; do
        dom="${dom_host%%:*}"
        host="${dom_host##*:}"
        addr="$(virsh domifaddr "$dom" --source agent 2>/dev/null | awk '/ipv4/ {print $4}' | cut -d/ -f1 | head -n1 || true)"
        if [ -z "$addr" ]; then
            info "$dom: no IP yet — skipping connectivity check"
            continue
        fi
        result="$(ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=10 -i "$SC_SSH_KEY" "player@$addr" hostname 2>/dev/null || echo FAIL)"
        if [ "$result" = "FAIL" ] || [ -z "$result" ]; then
            fail "$dom ($host): 'hostname' failed — check inetutils and shell PATH provisioning"
        fi
        ok "$dom ($host): hostname=$result"
    done
fi

# ---------------------------------------------------------------------------
# STEP 2 — Suppress guest maintenance noise
# ---------------------------------------------------------------------------

step "Suppressing guest maintenance noise"
info "Tuning base images to suppress package manager notices..."
for dom in sc-workstation sc-web-server sc-build-machine; do
    domain_selected "$dom" || continue
    if virsh dominfo "$dom" &>/dev/null 2>&1 || [ "$DRY_RUN" = "true" ]; then
        run bash "$VM_TOOLS/suppress-maintenance-noise.sh" "$dom" \
            $([ "$DRY_RUN" = "true" ] && echo "--dry-run")
        ok "$dom: maintenance noise suppressed"
    fi
done

# ---------------------------------------------------------------------------
# STEP 3 — Install guest helpers
# ---------------------------------------------------------------------------

step "Installing guest helpers"
info "Guest helpers are non-authoritative — advisory signals only."
for dom in sc-workstation sc-web-server sc-build-machine; do
    domain_selected "$dom" || continue
    if virsh dominfo "$dom" &>/dev/null 2>&1 || [ "$DRY_RUN" = "true" ]; then
        run bash "$VM_TOOLS/install-guest-helper.sh" "$dom" \
            $([ "$DRY_RUN" = "true" ] && echo "--dry-run")
        ok "$dom: guest helper installed"
    fi
done

# ---------------------------------------------------------------------------
# STEP 4 — Run quest-prep scripts and snapshot
# ---------------------------------------------------------------------------

step "Running quest-prep scripts and snapshotting"

run_prep_and_snapshot() {
    local quest_id="$1"
    local domain="$2"
    local snapshot_name="$3"
    local prep_script="$QUEST_PREP/${quest_id}-prep.sh"

    if [ ! -f "$prep_script" ]; then
        echo "  ⚠ No prep script found for $quest_id — skipping"
        return
    fi

    info "Running $quest_id prep on $domain..."
    run bash "$prep_script" "$domain" $([ "$DRY_RUN" = "true" ] && echo "--dry-run")

    info "Taking snapshot '$snapshot_name' on $domain..."
    run virsh snapshot-delete "$domain" "$snapshot_name" >/dev/null 2>&1 || true
    run virsh snapshot-create-as "$domain" "$snapshot_name" \
        --description "${quest_id} baseline — created by seed-vms.sh" \
        --atomic
    ok "$domain → $snapshot_name"
}

run_post_clean_and_snapshot() {
    local quest_id="$1"
    local domain="$2"
    local snapshot_name="$3"
    local clean_script="$QUEST_PREP/${quest_id}-post-clean.sh"

    if [ ! -f "$clean_script" ]; then
        echo "  ⚠ No post-clean script found for $quest_id — skipping"
        return
    fi

    info "Applying ${quest_id} clean branch state on $domain..."
    run bash "$clean_script" "$domain" $([ "$DRY_RUN" = "true" ] && echo "--dry-run")

    info "Taking snapshot '$snapshot_name' on $domain..."
    run virsh snapshot-delete "$domain" "$snapshot_name" >/dev/null 2>&1 || true
    run virsh snapshot-create-as "$domain" "$snapshot_name" \
        --description "${quest_id} clean branch baseline — created by seed-vms.sh" \
        --atomic
    ok "$domain → $snapshot_name"
}

# Q001: workstation day-one state
if vm_selected "workstation"; then
    run_prep_and_snapshot "Q001" "sc-workstation" "baseline.day-one"
fi

# Q002–Q004 share hermes clean baseline; prep scripts layer on top
if vm_selected "web_server"; then
    run_prep_and_snapshot "Q002" "sc-web-server"  "baseline.clean"
    run_prep_and_snapshot "Q003" "sc-web-server"  "baseline.post-q002"
    run_prep_and_snapshot "Q004" "sc-web-server"  "baseline.post-q003"
fi

# Q005 and Q007 use post-q004 baseline
if vm_selected "web_server"; then
    info "Creating baseline.post-q004 snapshot (used by Q005, Q007)..."
    run virsh snapshot-delete "sc-web-server" "baseline.post-q004" >/dev/null 2>&1 || true
    run virsh snapshot-create-as "sc-web-server" "baseline.post-q004" \
        --description "Post-Q004 baseline" --atomic || true
fi

# Q006: build machine broken baseline, then authored clean handoff for later quests
if vm_selected "build_machine"; then
    run_prep_and_snapshot "Q006" "sc-build-machine" "baseline.clean"
    run_post_clean_and_snapshot "Q006" "sc-build-machine" "baseline.post-q006"
fi

info "Q008 remains a multi-VM authored-state gap and is not provisioned by seed-vms.sh yet."

# Take recovery snapshots (always available as fallback)
step "Creating recovery snapshots"
for dom in sc-workstation sc-web-server sc-build-machine; do
    domain_selected "$dom" || continue
    info "Creating baseline.recovery on $dom..."
    run virsh snapshot-delete "$dom" "baseline.recovery" >/dev/null 2>&1 || true
    run virsh snapshot-create-as "$dom" "baseline.recovery" \
        --description "Recovery fallback — created by seed-vms.sh" \
        --atomic || true
    ok "$dom → baseline.recovery"
done

# ---------------------------------------------------------------------------

echo ""
echo "══════════════════════════════════════════════════"
echo "  Seed pipeline complete."
echo "  Verify with: bash tools/setup/check-host.sh"
echo "  Run content validation: bash tools/dev/test-content.sh"
echo "══════════════════════════════════════════════════"
echo ""
