#!/usr/bin/env bash
set -euo pipefail

# ===================================================================
# felhom-wipe.sh — Clean felhom data from a test node
# Usage: ./felhom-wipe.sh --level <soft|controller|full|nuclear> [--yes]
# ===================================================================

# --- Colors ---
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

# --- Defaults ---
LEVEL=""
DRY_RUN=true
INCLUDE_PROTECTED=false

# --- Configuration (auto-detected) ---
CONTROLLER_YAML="/opt/docker/felhom-controller/controller.yaml"
DATA_DIR="/opt/docker/felhom-controller/data"
COMPOSE_DIR="/opt/docker/felhom-controller"
STACKS_DIR="/opt/docker/stacks"
SETTINGS_JSON="$DATA_DIR/settings.json"

# --- Helpers ---
die()  { echo -e "${RED}ERROR: $1${NC}" >&2; exit 1; }
info() { echo -e "${GREEN}$1${NC}"; }
warn() { echo -e "${YELLOW}$1${NC}"; }
bold() { echo -e "${BOLD}$1${NC}"; }

human_size() {
    local path="$1"
    if [ -e "$path" ]; then
        du -sh "$path" 2>/dev/null | cut -f1 || echo "?"
    else
        echo "n/a"
    fi
}

usage() {
    cat <<EOF
Usage: $(basename "$0") --level <level> [--yes] [--include-protected]

Levels:
  soft        Controller state only (settings.json, metrics.db, session data)
  controller  Soft + remove all app containers, volumes, stack dirs, app.yaml files
  full        Controller + felhom-data/ on all drives (appdata, backups)
  nuclear     Full + controller.yaml, controller container, Traefik, Portainer, all Docker data

Options:
  --yes                Execute the wipe (default: dry run)
  --include-protected  Also remove protected stacks (controller level only)

EOF
    exit 1
}

# --- Parse Args ---
parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --level)       LEVEL="$2"; shift 2 ;;
            --yes)         DRY_RUN=false; shift ;;
            --include-protected) INCLUDE_PROTECTED=true; shift ;;
            -h|--help)     usage ;;
            *)             die "Unknown argument: $1" ;;
        esac
    done

    [[ -z "$LEVEL" ]] && usage
    case "$LEVEL" in
        soft|controller|full|nuclear) ;;
        *) die "Invalid level: $LEVEL (must be soft|controller|full|nuclear)" ;;
    esac
}

# --- Detect Paths ---
detect_paths() {
    # Auto-detect from controller.yaml if readable (may be root-owned)
    if [ -f "$CONTROLLER_YAML" ] && [ -r "$CONTROLLER_YAML" ]; then
        local sd
        sd=$(grep -oP 'stacks_dir:\s*\K\S+' "$CONTROLLER_YAML" 2>/dev/null || true)
        [ -n "$sd" ] && STACKS_DIR="$sd"
        local dd
        dd=$(grep -oP 'data_dir:\s*\K\S+' "$CONTROLLER_YAML" 2>/dev/null || true)
        [ -n "$dd" ] && DATA_DIR="$dd" && SETTINGS_JSON="$dd/settings.json"
    fi

    # If settings.json not found at configured path, try the Docker volume directly.
    # The controller stores data in a named volume (felhom-controller_controller-data),
    # not at the container-internal path on the host filesystem.
    if [ ! -f "$SETTINGS_JSON" ]; then
        local vol_path
        vol_path=$(docker volume inspect felhom-controller_controller-data --format '{{.Mountpoint}}' 2>/dev/null || true)
        if [ -n "$vol_path" ] && [ -d "$vol_path" ]; then
            DATA_DIR="$vol_path"
            SETTINGS_JSON="$vol_path/settings.json"
        fi
    fi
}

# --- Detect Storage Paths ---
declare -a STORAGE_PATHS=()

detect_storage_paths() {
    # From settings.json
    if [ -f "$SETTINGS_JSON" ]; then
        while IFS= read -r p; do
            [ -n "$p" ] && STORAGE_PATHS+=("$p")
        done < <(python3 -c "
import json, sys
try:
    d = json.load(open('$SETTINGS_JSON'))
    for sp in d.get('storage_paths', []):
        print(sp.get('path', ''))
except: pass
" 2>/dev/null || true)
    fi

    # Also scan /mnt/* for felhom-managed dirs not in registry.
    # Detect by presence of felhom-data/, legacy appdata/backups/, or .felhom-infra-backup/
    for d in /mnt/*/; do
        [ -d "${d}felhom-data" ] || [ -d "${d}appdata" ] || [ -d "${d}backups" ] \
            || [ -d "${d}.felhom-infra-backup" ] || continue
        local already=false
        for sp in "${STORAGE_PATHS[@]:-}"; do
            [ "$sp" = "${d%/}" ] && already=true && break
        done
        $already || STORAGE_PATHS+=("${d%/}")
    done
}

# --- List App Containers (non-infra) ---
list_app_containers() {
    docker ps -a --format '{{.Names}}' 2>/dev/null | grep -v -E '^(felhom-controller|traefik|cloudflared|portainer)$' || true
}

# --- List App Volumes (non-infra) ---
list_app_volumes() {
    docker volume ls -q 2>/dev/null | grep -v -E '^(portainer_data)$' || true
}

# --- Protected Stacks ---
get_protected_stacks() {
    if [ -f "$CONTROLLER_YAML" ]; then
        grep -A 20 'protected_stacks:' "$CONTROLLER_YAML" 2>/dev/null | grep -oP '^\s*-\s*\K\S+' || true
    fi
}

# --- Print Plan ---
print_plan() {
    echo ""
    bold "=== Felhom Wipe — Level: $LEVEL ==="
    echo ""

    # State files
    echo -e "${CYAN}Controller state:${NC}"
    local state_files=("$DATA_DIR/settings.json" "$DATA_DIR/metrics.db" "$DATA_DIR/setup-state.json" "$DATA_DIR/update-state.json" "$DATA_DIR/session-data.json" "$DATA_DIR/snapshot-history.json")
    for f in "${state_files[@]}"; do
        if [ -f "$f" ]; then
            echo -e "  ${YELLOW}DELETE${NC} $f ($(human_size "$f"))"
        fi
    done

    if [[ "$LEVEL" == "controller" || "$LEVEL" == "full" || "$LEVEL" == "nuclear" ]]; then
        echo ""
        echo -e "${CYAN}Docker containers:${NC}"
        local containers
        containers=$(list_app_containers)
        if [ -n "$containers" ]; then
            echo "$containers" | while read -r c; do
                echo -e "  ${YELLOW}REMOVE${NC} $c"
            done
        else
            echo -e "  ${GREEN}(none)${NC}"
        fi

        echo ""
        echo -e "${CYAN}Docker volumes:${NC}"
        local volumes
        volumes=$(list_app_volumes)
        if [ -n "$volumes" ]; then
            echo "$volumes" | while read -r v; do
                echo -e "  ${YELLOW}REMOVE${NC} $v"
            done
        else
            echo -e "  ${GREEN}(none)${NC}"
        fi

        echo ""
        echo -e "${CYAN}Stack directories:${NC}"
        if [ -d "$STACKS_DIR" ]; then
            for sd in "$STACKS_DIR"/*/; do
                [ -d "$sd" ] || continue
                local stack_name
                stack_name=$(basename "$sd")
                local protected_stacks
                protected_stacks=$(get_protected_stacks)
                if echo "$protected_stacks" | grep -qx "$stack_name" && ! $INCLUDE_PROTECTED; then
                    echo -e "  ${GREEN}KEEP${NC}   $sd (protected)"
                else
                    echo -e "  ${YELLOW}DELETE${NC} $sd"
                fi
            done
        else
            echo -e "  ${GREEN}(not found)${NC}"
        fi
    fi

    if [[ "$LEVEL" == "full" || "$LEVEL" == "nuclear" ]]; then
        echo ""
        echo -e "${CYAN}Mount cleanup:${NC}"
        if [ -d /mnt/.felhom-scan ]; then
            echo -e "  ${YELLOW}DELETE${NC} /mnt/.felhom-scan/ (stale scan dir)"
        else
            echo -e "  ${GREEN}(no .felhom-scan dir)${NC}"
        fi
    fi

    if [[ "$LEVEL" == "full" || "$LEVEL" == "nuclear" ]]; then
        echo ""
        echo -e "${CYAN}Storage data:${NC}"
        if [ ${#STORAGE_PATHS[@]} -gt 0 ]; then
            for sp in "${STORAGE_PATHS[@]}"; do
                if [ -d "$sp/felhom-data" ]; then
                    echo -e "  ${YELLOW}DELETE${NC} $sp/felhom-data/ ($(human_size "$sp/felhom-data"))"
                fi
                # Old-style paths
                if [ -d "$sp/appdata" ]; then
                    echo -e "  ${YELLOW}DELETE${NC} $sp/appdata/ ($(human_size "$sp/appdata")) [old-style]"
                fi
                if [ -d "$sp/backups" ]; then
                    echo -e "  ${YELLOW}DELETE${NC} $sp/backups/ ($(human_size "$sp/backups")) [old-style]"
                fi
            done
        else
            echo -e "  ${GREEN}(no storage paths found)${NC}"
        fi
    fi

    if [[ "$LEVEL" == "nuclear" ]]; then
        echo ""
        echo -e "${RED}Nuclear:${NC}"
        echo -e "  ${RED}DELETE${NC} controller.yaml"
        echo -e "  ${RED}DELETE${NC} controller container + image"
        echo -e "  ${RED}DELETE${NC} Traefik container"
        echo -e "  ${RED}DELETE${NC} Cloudflared container"
        echo -e "  ${RED}DELETE${NC} Portainer container + volume"
        echo -e "  ${RED}DELETE${NC} .felhom-infra-backup/ (DR markers on detected drives):"
        local dr_found=false
        for sp in "${STORAGE_PATHS[@]:-}"; do
            if [ -d "$sp/.felhom-infra-backup" ]; then
                echo -e "    ${RED}DELETE${NC} $sp/.felhom-infra-backup/"
                dr_found=true
            fi
        done
        $dr_found || echo -e "    ${GREEN}(none found)${NC}"
        if [ -d /mnt/.felhom-raw ]; then
            echo -e "  ${RED}UNMOUNT+DELETE${NC} /mnt/.felhom-raw/ (raw helper mounts + fstab entries)"
            # Show each raw mount and its bind target
            for rmp in /mnt/.felhom-raw/*/; do
                [ -d "$rmp" ] || continue
                local label; label=$(basename "$rmp")
                local bind_target
                bind_target=$(grep -E "^/mnt/\.felhom-raw/${label}/" /etc/fstab 2>/dev/null | awk '{print $2}' | head -1 || true)
                if [ -n "$bind_target" ]; then
                    echo -e "    ${RED}umount + rmdir${NC} ${bind_target} (bind) → ${rmp} (raw)"
                else
                    echo -e "    ${RED}umount${NC} ${rmp} (raw, no bind found)"
                fi
            done
        fi
        echo -e "  ${RED}DELETE${NC} All Docker data (docker system prune -af --volumes)"
        echo -e "  ${RED}DELETE${NC} $COMPOSE_DIR/ (controller compose + .env)"
        local infra_root; infra_root=$(dirname "$COMPOSE_DIR")
        echo -e "  ${RED}DELETE${NC} $infra_root/traefik/ (configs + acme.json)"
        echo -e "  ${RED}DELETE${NC} $infra_root/cloudflared/ (configs)"
        echo -e "  ${RED}DELETE${NC} $STACKS_DIR/ (empty stacks dir)"
    fi

    echo ""
    echo -e "${CYAN}Will preserve:${NC}"
    echo -e "  ${GREEN}- OS and system files${NC}"
    if [[ "$LEVEL" != "nuclear" ]]; then
        echo -e "  ${GREEN}- Controller container (felhom-controller)${NC}"
        echo -e "  ${GREEN}- Controller image${NC}"
        echo -e "  ${GREEN}- Traefik, Cloudflare Tunnel${NC}"
        echo -e "  ${GREEN}- controller.yaml${NC}"
        echo -e "  ${GREEN}- .felhom-infra-backup/ (DR markers on drives)${NC}"
    fi
    if [[ "$LEVEL" != "full" && "$LEVEL" != "nuclear" ]]; then
        echo -e "  ${GREEN}- Storage data on drives${NC}"
    fi
    echo -e "  ${GREEN}- User files (Dokumentumok, media, etc.)${NC}"
    echo ""
}

# --- Mount Cleanup Helpers ---

# cleanup_scan_dir: remove /mnt/.felhom-scan/ (ephemeral DR scan staging dir).
# Always empty after normal operation; safe to rm -rf unconditionally.
cleanup_scan_dir() {
    if [ -d /mnt/.felhom-scan ]; then
        rm -rf /mnt/.felhom-scan && info "  Removed: /mnt/.felhom-scan/"
    fi
}

# cleanup_raw_mounts: unmount bind mounts, unmount raw helper mounts, strip
# /etc/fstab entries, then remove the now-empty /mnt/.felhom-raw/ directory.
#
# Raw mounts are created by the attach wizard (two-level: raw partition mount +
# bind mount from subfolder). Both fstab entries must be removed so they don't
# cause errors on next boot.  Order: bind umount first, then raw umount.
cleanup_raw_mounts() {
    [ -d /mnt/.felhom-raw ] || return

    info "Cleaning up raw helper mounts (/mnt/.felhom-raw/)..."

    # 1. Unmount bind mounts whose source is inside .felhom-raw (field 1 matches)
    #    Collect targets first so we can rmdir them after unmounting.
    local bind_targets=""
    if [ -f /etc/fstab ]; then
        bind_targets=$(grep -E '^/mnt/\.felhom-raw/' /etc/fstab | awk '{print $2}' || true)
        for mp in $bind_targets; do
            if mountpoint -q "$mp" 2>/dev/null; then
                umount -l "$mp" 2>/dev/null && info "  Unmounted bind: $mp" \
                    || warn "  Could not unmount bind: $mp"
            fi
        done
    fi

    # 2. Unmount raw partition mounts (field 2 matches /mnt/.felhom-raw/*)
    for mp in /mnt/.felhom-raw/*/; do
        [ -d "$mp" ] || continue
        if mountpoint -q "$mp" 2>/dev/null; then
            umount -l "$mp" 2>/dev/null && info "  Unmounted raw: $mp" \
                || warn "  Could not unmount raw: $mp"
        fi
    done

    # 3. Strip all .felhom-raw entries from fstab (both raw and bind lines)
    if [ -f /etc/fstab ] && grep -q '\.felhom-raw' /etc/fstab 2>/dev/null; then
        sed -i '\|\.felhom-raw|d' /etc/fstab && info "  Removed .felhom-raw entries from /etc/fstab"
    fi

    # 4. Remove /mnt/.felhom-raw/ — safe now that mounts are gone
    rm -rf /mnt/.felhom-raw && info "  Removed: /mnt/.felhom-raw/"

    # 5. Remove the now-empty bind target directories (e.g. /mnt/hdd_1).
    #    Use rmdir so we only remove them if truly empty — never touch user data.
    for mp in $bind_targets; do
        if [ -d "$mp" ]; then
            rmdir "$mp" 2>/dev/null && info "  Removed mount point: $mp" \
                || warn "  Could not remove (not empty?): $mp"
        fi
    done
}

# --- Wipe Functions ---

do_soft_wipe() {
    info "Soft wipe: removing controller state..."
    local state_files=("$DATA_DIR/settings.json" "$DATA_DIR/metrics.db" "$DATA_DIR/setup-state.json" "$DATA_DIR/update-state.json" "$DATA_DIR/session-data.json" "$DATA_DIR/snapshot-history.json")
    for f in "${state_files[@]}"; do
        if [ -f "$f" ]; then rm -f "$f" && info "  Removed: $f"; fi
    done
}

do_controller_wipe() {
    do_soft_wipe

    info "Controller wipe: stopping and removing app containers..."

    # Stop and remove app containers
    local containers
    containers=$(list_app_containers)
    if [ -n "$containers" ]; then
        echo "$containers" | while read -r c; do
            docker rm -f "$c" 2>/dev/null && info "  Removed container: $c" || warn "  Failed to remove: $c"
        done
    fi

    # Remove app volumes
    info "Removing app volumes..."
    local volumes
    volumes=$(list_app_volumes)
    if [ -n "$volumes" ]; then
        echo "$volumes" | while read -r v; do
            docker volume rm "$v" 2>/dev/null && info "  Removed volume: $v" || warn "  Failed to remove: $v"
        done
    fi

    # Remove stack directories
    info "Removing stack directories..."
    if [ -d "$STACKS_DIR" ]; then
        local protected_stacks
        protected_stacks=$(get_protected_stacks)
        for sd in "$STACKS_DIR"/*/; do
            [ -d "$sd" ] || continue
            local stack_name
            stack_name=$(basename "$sd")
            if echo "$protected_stacks" | grep -qx "$stack_name" && ! $INCLUDE_PROTECTED; then
                warn "  Skipping protected stack: $stack_name"
                continue
            fi
            rm -rf "$sd" && info "  Removed: $sd"
        done
    fi

    # NOTE: No restart here — callers handle restart after all cleanup is done.
}

do_full_wipe() {
    do_controller_wipe

    info "Full wipe: removing storage data..."
    for sp in "${STORAGE_PATHS[@]}"; do
        # New-style namespace
        if [ -d "$sp/felhom-data" ]; then
            rm -rf "$sp/felhom-data" && info "  Removed: $sp/felhom-data/"
        fi
        # Old-style paths
        if [ -d "$sp/appdata" ]; then
            rm -rf "$sp/appdata" && info "  Removed: $sp/appdata/ [old-style]"
        fi
        if [ -d "$sp/backups" ]; then
            rm -rf "$sp/backups" && info "  Removed: $sp/backups/ [old-style]"
        fi
    done

    # Remove stale scan dir (ephemeral DR staging — always safe to remove)
    cleanup_scan_dir

    # Restart controller after all cleanup is done
    info "Restarting controller..."
    docker restart felhom-controller 2>/dev/null || warn "Could not restart controller"
}

do_nuclear_wipe() {
    do_full_wipe

    info "Nuclear wipe: removing all infrastructure..."

    # Stop infrastructure containers
    for c in felhom-controller traefik cloudflared portainer; do
        docker rm -f "$c" 2>/dev/null && info "  Removed: $c" || true
    done

    # Remove DR markers (nuclear = brand-new machine simulation)
    for sp in "${STORAGE_PATHS[@]}"; do
        if [ -d "$sp/.felhom-infra-backup" ]; then
            rm -rf "$sp/.felhom-infra-backup" && info "  Removed: $sp/.felhom-infra-backup/"
        fi
    done

    # Unmount raw helper mounts, strip fstab entries, remove dirs
    # (scan dir already removed by do_full_wipe above)
    cleanup_raw_mounts

    # Remove all Docker data
    warn "Pruning all Docker data..."
    docker system prune -af --volumes 2>/dev/null || warn "Docker prune failed"

    # Remove infra config directories (after prune so containers are gone)
    local infra_root
    infra_root=$(dirname "$COMPOSE_DIR")
    rm -rf "$COMPOSE_DIR"   && info "  Removed: $COMPOSE_DIR/"
    rm -rf "$infra_root/traefik"     && info "  Removed: $infra_root/traefik/"
    rm -rf "$infra_root/cloudflared" && info "  Removed: $infra_root/cloudflared/"
    rm -rf "$STACKS_DIR"    && info "  Removed: $STACKS_DIR/"

    # Remove any leftover empty mount point dirs under /mnt/ (e.g. /mnt/hdd_1 after
    # the bind mount was already cleaned by a prior wipe run). rmdir is safe: it
    # refuses to remove non-empty directories, so user data is never at risk.
    for mp in /mnt/*/; do
        [ -d "$mp" ] || continue
        rmdir "$mp" 2>/dev/null && info "  Removed empty mount point: $mp" || true
    done

    echo ""
    info "Nuclear wipe complete."
    echo -e "${CYAN}To redeploy, run:${NC}"
    echo "  curl -fsSL https://gitea.dooplex.hu/admin/felhom-controller/raw/branch/main/scripts/docker-setup.sh | bash"
}

# --- Main ---
main() {
    # Must run as root
    if [ "$(id -u)" -ne 0 ]; then
        die "Must run as root (use sudo)"
    fi

    # Check Docker
    if ! docker info >/dev/null 2>&1; then
        die "Docker is not running"
    fi

    parse_args "$@"
    detect_paths
    detect_storage_paths
    print_plan

    if $DRY_RUN; then
        warn "Dry run — nothing deleted. Use --yes to execute."
        exit 0
    fi

    # Confirmation
    echo -e "${RED}${BOLD}This will permanently delete the data listed above.${NC}"
    read -rp "Type YES to confirm: " confirm
    if [ "$confirm" != "YES" ]; then
        echo "Aborted."
        exit 1
    fi

    echo ""
    case "$LEVEL" in
        soft)       do_soft_wipe ;;
        controller) do_controller_wipe
                    info "Restarting controller..."
                    docker restart felhom-controller 2>/dev/null || warn "Could not restart controller"
                    ;;
        full)       do_full_wipe ;;
        nuclear)    do_nuclear_wipe ;;
    esac

    echo ""
    info "Wipe complete (level: $LEVEL)."
}

main "$@"
