#!/bin/sh
# SecuBox Recover - Self-Revival & Recovery System
# Full backup/restore with distributed mesh support
# Copyright 2026 CyberMind

set -e

# ============================================================================
# Configuration
# ============================================================================
RECOVER_DIR="/srv/secubox/recover"
ARCHIVE_DIR="$RECOVER_DIR/archives"
CATALOG_FILE="$RECOVER_DIR/catalog.json"
HISTORY_FILE="$RECOVER_DIR/history.json"
PROFILES_DIR="$RECOVER_DIR/profiles"
APPS_DIR="$RECOVER_DIR/apps"

# Mesh integration
MESH_BIN="/usr/sbin/secubox-mesh"
MESH_ENABLED=1

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

log() { echo -e "${CYAN}[RECOVER]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }

# ============================================================================
# Initialization
# ============================================================================
init() {
    mkdir -p "$ARCHIVE_DIR" "$PROFILES_DIR" "$APPS_DIR" "$RECOVER_DIR/tmp"

    # Initialize catalog
    [ ! -f "$CATALOG_FILE" ] && cat > "$CATALOG_FILE" << EOF
{
    "version": 1,
    "node": "$(cat /srv/secubox/mesh/node.id 2>/dev/null || hostname)",
    "created": "$(date -Iseconds)",
    "apps": [],
    "profiles": [],
    "snapshots": []
}
EOF

    # Initialize history
    [ ! -f "$HISTORY_FILE" ] && cat > "$HISTORY_FILE" << EOF
{
    "version": 1,
    "entries": []
}
EOF

    log "Recovery system initialized"
}

# ============================================================================
# Full System Snapshot
# ============================================================================
snapshot_full() {
    local name="${1:-full-$(date +%Y%m%d-%H%M%S)}"
    local archive="$ARCHIVE_DIR/$name.tar.gz"

    log "Creating full system snapshot: $name"

    local tmp_dir="$RECOVER_DIR/tmp/$name"
    mkdir -p "$tmp_dir"

    # 1. System configs
    log "  Backing up system configs..."
    cp -a /etc/config "$tmp_dir/etc-config" 2>/dev/null || true

    # 2. SecuBox specific
    log "  Backing up SecuBox data..."
    mkdir -p "$tmp_dir/secubox"
    cp -a /srv/secubox "$tmp_dir/secubox/srv" 2>/dev/null || true
    cp -a /opt/haproxy "$tmp_dir/secubox/haproxy" 2>/dev/null || true
    cp -a /opt/containers "$tmp_dir/secubox/containers" 2>/dev/null || true

    # 3. Installed packages
    log "  Recording installed packages..."
    opkg list-installed > "$tmp_dir/packages.list"
    opkg list-user-installed > "$tmp_dir/packages-user.list" 2>/dev/null || true

    # 4. Network config
    log "  Backing up network state..."
    ip addr > "$tmp_dir/ip-addr.txt" 2>/dev/null || true
    ip route > "$tmp_dir/ip-route.txt" 2>/dev/null || true

    # 5. Service states
    log "  Recording service states..."
    for svc in /etc/init.d/*; do
        [ -x "$svc" ] && echo "$(basename $svc): $($svc enabled && echo enabled || echo disabled)" >> "$tmp_dir/services.txt"
    done 2>/dev/null || true

    # 6. Crontabs
    cp -a /etc/crontabs "$tmp_dir/crontabs" 2>/dev/null || true

    # 7. SSL certificates
    log "  Backing up certificates..."
    mkdir -p "$tmp_dir/certs"
    cp -a /etc/ssl "$tmp_dir/certs/etc-ssl" 2>/dev/null || true
    cp -a /opt/haproxy/certs "$tmp_dir/certs/haproxy" 2>/dev/null || true
    cp -a /srv/mitmproxy/*.pem "$tmp_dir/certs/mitmproxy" 2>/dev/null || true

    # 8. Create manifest
    cat > "$tmp_dir/manifest.json" << EOF
{
    "name": "$name",
    "type": "full",
    "created": "$(date -Iseconds)",
    "hostname": "$(uci get system.@system[0].hostname 2>/dev/null || hostname)",
    "version": "$(cat /etc/secubox-version 2>/dev/null || echo unknown)",
    "openwrt": "$(cat /etc/openwrt_release | grep DISTRIB_RELEASE | cut -d= -f2 | tr -d "'")",
    "files": $(find "$tmp_dir" -type f | wc -l),
    "size_bytes": $(du -sb "$tmp_dir" | cut -f1)
}
EOF

    # 9. Create restore script
    cat > "$tmp_dir/restore.sh" << 'RESTORE'
#!/bin/sh
# SecuBox Snapshot Restore Script
echo "=== SecuBox Snapshot Restore ==="
echo "Restoring from: $(cat manifest.json | jsonfilter -e '@.name')"

# Restore configs
echo "Restoring configs..."
cp -a etc-config/* /etc/config/ 2>/dev/null

# Restore SecuBox data
echo "Restoring SecuBox data..."
cp -a secubox/srv/* /srv/secubox/ 2>/dev/null
cp -a secubox/haproxy/* /opt/haproxy/ 2>/dev/null

# Restore certs
echo "Restoring certificates..."
cp -a certs/etc-ssl/* /etc/ssl/ 2>/dev/null
cp -a certs/haproxy/* /opt/haproxy/certs/ 2>/dev/null

# Reinstall user packages
echo "Reinstalling packages..."
if [ -f packages-user.list ]; then
    opkg update
    cat packages-user.list | cut -d' ' -f1 | xargs opkg install 2>/dev/null || true
fi

# Reload services
echo "Reloading services..."
/etc/init.d/network reload 2>/dev/null || true
/etc/init.d/haproxy restart 2>/dev/null || true
/etc/init.d/rpcd restart 2>/dev/null || true

echo "=== Restore Complete ==="
echo "Please reboot to apply all changes"
RESTORE
    chmod +x "$tmp_dir/restore.sh"

    # 10. Archive
    log "  Creating archive..."
    tar -czf "$archive" -C "$RECOVER_DIR/tmp" "$name"
    rm -rf "$tmp_dir"

    # 11. Calculate hash
    local hash=$(sha256sum "$archive" | cut -d' ' -f1)

    # 12. Update catalog
    add_to_catalog "snapshots" "$name" "$hash" "$(stat -c%s "$archive")" "full"

    # 13. Add to history
    add_to_history "snapshot" "$name" "$hash"

    # 14. Publish to mesh
    if [ "$MESH_ENABLED" = "1" ] && [ -x "$MESH_BIN" ]; then
        log "  Publishing to mesh..."
        $MESH_BIN snapshot "$name" 2>/dev/null || true
    fi

    success "Snapshot created: $archive"
    echo "Hash: $hash"
    echo "Size: $(du -h "$archive" | cut -f1)"
}

# ============================================================================
# Profile Management
# ============================================================================
profile_save() {
    local name="${1:-profile-$(date +%Y%m%d)}"
    local profile_file="$PROFILES_DIR/$name.json"

    log "Saving profile: $name"

    # Extract current configuration as profile
    cat > "$profile_file" << EOF
{
    "name": "$name",
    "created": "$(date -Iseconds)",
    "hostname": "$(uci get system.@system[0].hostname 2>/dev/null)",
    "network": {
        "lan_ip": "$(uci get network.lan.ipaddr 2>/dev/null)",
        "wan_proto": "$(uci get network.wan.proto 2>/dev/null)"
    },
    "secubox": {
        "theme": "$(uci get secubox.ui.theme 2>/dev/null || echo default)",
        "modules": $(uci show secubox 2>/dev/null | grep enabled | grep -c '=1' || echo 0)
    },
    "haproxy": {
        "enabled": $(uci get haproxy.main.enabled 2>/dev/null || echo 0),
        "vhosts": $(uci show haproxy 2>/dev/null | grep -c '=vhost' || echo 0)
    },
    "apps": [
$(opkg list-user-installed 2>/dev/null | while read pkg; do
    echo "        \"$(echo $pkg | cut -d' ' -f1)\","
done | sed '$ s/,$//')
    ]
}
EOF

    local hash=$(sha256sum "$profile_file" | cut -d' ' -f1 | head -c 16)
    add_to_catalog "profiles" "$name" "$hash" "$(stat -c%s "$profile_file")" "profile"
    add_to_history "profile_save" "$name" "$hash"

    success "Profile saved: $profile_file"
}

profile_apply() {
    local name="$1"
    local profile_file="$PROFILES_DIR/$name.json"

    if [ ! -f "$profile_file" ]; then
        error "Profile not found: $name"
        return 1
    fi

    log "Applying profile: $name"

    # Apply settings from profile
    local hostname=$(jsonfilter -i "$profile_file" -e '@.hostname')
    [ -n "$hostname" ] && uci set system.@system[0].hostname="$hostname"

    local lan_ip=$(jsonfilter -i "$profile_file" -e '@.network.lan_ip')
    [ -n "$lan_ip" ] && uci set network.lan.ipaddr="$lan_ip"

    local theme=$(jsonfilter -i "$profile_file" -e '@.secubox.theme')
    [ -n "$theme" ] && uci set secubox.ui.theme="$theme"

    uci commit

    add_to_history "profile_apply" "$name" ""
    success "Profile applied: $name"
}

profile_list() {
    log "Available profiles:"
    for f in "$PROFILES_DIR"/*.json; do
        [ -f "$f" ] || continue
        local name=$(basename "$f" .json)
        local created=$(jsonfilter -i "$f" -e '@.created' 2>/dev/null)
        echo "  - $name ($created)"
    done
}

# ============================================================================
# Apps Catalog
# ============================================================================
apps_sync() {
    log "Syncing apps catalog..."

    # Create local apps catalog from installed packages
    local apps_file="$APPS_DIR/installed.json"

    cat > "$apps_file" << EOF
{
    "synced": "$(date -Iseconds)",
    "apps": [
EOF

    local first=1
    opkg list-installed | while read line; do
        local pkg=$(echo "$line" | cut -d' ' -f1)
        local ver=$(echo "$line" | cut -d' ' -f3)

        [ $first -eq 0 ] && echo "," >> "$apps_file"
        first=0

        cat >> "$apps_file" << APPEOF
        {
            "name": "$pkg",
            "version": "$ver",
            "installed": true
        }
APPEOF
    done

    echo "    ]}" >> "$apps_file"

    success "Apps catalog synced: $(opkg list-installed | wc -l) packages"
}

apps_export() {
    local output="${1:-$APPS_DIR/apps-export-$(date +%Y%m%d).list}"

    opkg list-user-installed > "$output" 2>/dev/null
    success "Apps exported: $output"
}

apps_import() {
    local input="$1"

    if [ ! -f "$input" ]; then
        error "Apps list not found: $input"
        return 1
    fi

    log "Importing apps from: $input"
    opkg update

    cat "$input" | cut -d' ' -f1 | while read pkg; do
        log "  Installing: $pkg"
        opkg install "$pkg" 2>/dev/null || warn "Failed: $pkg"
    done

    success "Apps import complete"
}

# ============================================================================
# History & Rollback
# ============================================================================
add_to_history() {
    local action="$1"
    local target="$2"
    local hash="$3"

    local tmp_hist="$RECOVER_DIR/tmp/history_$$.json"
    local entry="{\"timestamp\":\"$(date -Iseconds)\",\"action\":\"$action\",\"target\":\"$target\",\"hash\":\"$hash\"}"

    if [ -f "$HISTORY_FILE" ]; then
        jsonfilter -i "$HISTORY_FILE" -e '@' | \
            sed "s/\"entries\":\[/\"entries\":[$entry,/" > "$tmp_hist"
        mv "$tmp_hist" "$HISTORY_FILE"
    fi
}

history_show() {
    local limit="${1:-20}"

    log "Recent history (last $limit entries):"
    jsonfilter -i "$HISTORY_FILE" -e '@.entries[*]' 2>/dev/null | head -$limit | while read entry; do
        local ts=$(echo "$entry" | jsonfilter -e '@.timestamp')
        local action=$(echo "$entry" | jsonfilter -e '@.action')
        local target=$(echo "$entry" | jsonfilter -e '@.target')
        echo "  [$ts] $action: $target"
    done
}

rollback() {
    local target="$1"

    if [ -z "$target" ]; then
        # Find last snapshot
        target=$(ls -t "$ARCHIVE_DIR"/*.tar.gz 2>/dev/null | head -1)
    fi

    if [ ! -f "$target" ] && [ -f "$ARCHIVE_DIR/$target.tar.gz" ]; then
        target="$ARCHIVE_DIR/$target.tar.gz"
    fi

    if [ ! -f "$target" ]; then
        error "No snapshot found for rollback"
        return 1
    fi

    log "Rolling back to: $target"
    warn "This will overwrite current configuration!"

    # Extract and run restore
    local tmp_dir="$RECOVER_DIR/tmp/rollback_$$"
    mkdir -p "$tmp_dir"
    tar -xzf "$target" -C "$tmp_dir"

    cd "$tmp_dir"/*
    ./restore.sh

    cd /
    rm -rf "$tmp_dir"

    add_to_history "rollback" "$(basename $target)" ""
    success "Rollback complete"
}

# ============================================================================
# Catalog Management
# ============================================================================
add_to_catalog() {
    local cat_type="$1"
    local name="$2"
    local hash="$3"
    local size="$4"
    local item_type="$5"

    local tmp_cat="$RECOVER_DIR/tmp/catalog_$$.json"
    local entry="{\"name\":\"$name\",\"hash\":\"$hash\",\"size\":$size,\"type\":\"$item_type\",\"created\":\"$(date -Iseconds)\"}"

    jsonfilter -i "$CATALOG_FILE" -e '@' | \
        sed "s/\"$cat_type\":\[/\"$cat_type\":[$entry,/" > "$tmp_cat"
    mv "$tmp_cat" "$CATALOG_FILE"
}

catalog_show() {
    log "Recovery Catalog:"
    echo ""
    echo "=== Snapshots ==="
    jsonfilter -i "$CATALOG_FILE" -e '@.snapshots[*]' 2>/dev/null | while read item; do
        local name=$(echo "$item" | jsonfilter -e '@.name')
        local size=$(echo "$item" | jsonfilter -e '@.size')
        local created=$(echo "$item" | jsonfilter -e '@.created')
        echo "  $name ($(numfmt --to=iec $size 2>/dev/null || echo ${size}B)) - $created"
    done

    echo ""
    echo "=== Profiles ==="
    jsonfilter -i "$CATALOG_FILE" -e '@.profiles[*]' 2>/dev/null | while read item; do
        local name=$(echo "$item" | jsonfilter -e '@.name')
        echo "  $name"
    done
}

# ============================================================================
# Reborn Script Generator
# ============================================================================
generate_reborn() {
    local output="${1:-/tmp/secubox-reborn.sh}"

    log "Generating reborn script..."

    # Create fresh snapshot first
    local snapshot_name="reborn-$(date +%Y%m%d-%H%M%S)"
    snapshot_full "$snapshot_name"

    local archive="$ARCHIVE_DIR/$snapshot_name.tar.gz"
    local hash=$(sha256sum "$archive" | cut -d' ' -f1)

    # Get mesh peers
    local peers=""
    if [ -x "$MESH_BIN" ]; then
        peers=$($MESH_BIN peer-list 2>/dev/null | jsonfilter -e '@.addr' | tr '\n' ' ')
    fi

    # Generate self-contained script
    cat > "$output" << REBORN
#!/bin/sh
# ============================================================================
# SecuBox Reborn Script - Self-Revival Bootstrap
# Generated: $(date -Iseconds)
# Snapshot: $snapshot_name
# Hash: $hash
# ============================================================================

echo "╔══════════════════════════════════════════════════════════════╗"
echo "║           SecuBox Reborn - Self-Revival System               ║"
echo "╠══════════════════════════════════════════════════════════════╣"
echo "║  Snapshot: $snapshot_name"
echo "║  Hash: ${hash:0:16}..."
echo "╚══════════════════════════════════════════════════════════════╝"

SNAPSHOT_HASH="$hash"
MESH_PEERS="$peers"
ARCHIVE_URL=""

# Embedded snapshot (base64)
EMBEDDED_ARCHIVE="
$(base64 -w0 "$archive" 2>/dev/null || base64 "$archive")
"

recover_from_embedded() {
    echo "[1/4] Extracting embedded archive..."
    echo "\$EMBEDDED_ARCHIVE" | base64 -d > /tmp/snapshot.tar.gz

    verify_and_restore
}

recover_from_mesh() {
    echo "[1/4] Fetching from mesh peers..."
    for peer in \$MESH_PEERS; do
        echo "  Trying: \$peer"
        if curl -sf "http://\$peer:7331/api/block/\$SNAPSHOT_HASH" -o /tmp/snapshot.tar.gz 2>/dev/null; then
            echo "  Downloaded from \$peer"
            verify_and_restore
            return 0
        fi
    done
    echo "  Failed to fetch from mesh"
    return 1
}

recover_from_url() {
    if [ -n "\$ARCHIVE_URL" ]; then
        echo "[1/4] Downloading from URL..."
        curl -sfL "\$ARCHIVE_URL" -o /tmp/snapshot.tar.gz
        verify_and_restore
    fi
}

verify_and_restore() {
    echo "[2/4] Verifying integrity..."
    local actual=\$(sha256sum /tmp/snapshot.tar.gz | cut -d' ' -f1)
    if [ "\$actual" != "\$SNAPSHOT_HASH" ]; then
        echo "ERROR: Hash mismatch!"
        echo "  Expected: \$SNAPSHOT_HASH"
        echo "  Got: \$actual"
        exit 1
    fi
    echo "  Hash verified OK"

    echo "[3/4] Extracting snapshot..."
    mkdir -p /tmp/secubox-restore
    tar -xzf /tmp/snapshot.tar.gz -C /tmp/secubox-restore

    echo "[4/4] Running restore..."
    cd /tmp/secubox-restore/*
    chmod +x restore.sh
    ./restore.sh

    echo ""
    echo "╔══════════════════════════════════════════════════════════════╗"
    echo "║              SecuBox Reborn Complete!                        ║"
    echo "╚══════════════════════════════════════════════════════════════╝"
    echo ""
    echo "Please reboot to apply all changes: reboot"
}

# Main
case "\$1" in
    --mesh)
        recover_from_mesh || recover_from_embedded
        ;;
    --url)
        ARCHIVE_URL="\$2"
        recover_from_url
        ;;
    *)
        recover_from_embedded
        ;;
esac
REBORN

    chmod +x "$output"
    success "Reborn script generated: $output"
    echo "Size: $(du -h "$output" | cut -f1)"
    echo ""
    echo "Usage:"
    echo "  $output           # Restore from embedded archive"
    echo "  $output --mesh    # Try mesh peers first"
}

# ============================================================================
# Main
# ============================================================================
init

case "$1" in
    snapshot)
        snapshot_full "$2"
        ;;
    restore|rollback)
        rollback "$2"
        ;;
    profile-save)
        profile_save "$2"
        ;;
    profile-apply)
        profile_apply "$2"
        ;;
    profile-list|profiles)
        profile_list
        ;;
    apps-sync)
        apps_sync
        ;;
    apps-export)
        apps_export "$2"
        ;;
    apps-import)
        apps_import "$2"
        ;;
    history)
        history_show "$2"
        ;;
    catalog)
        catalog_show
        ;;
    reborn)
        generate_reborn "$2"
        ;;
    *)
        echo "SecuBox Recover - Self-Revival & Recovery System"
        echo ""
        echo "Usage: $0 <command> [args]"
        echo ""
        echo "Snapshots:"
        echo "  snapshot [name]      Create full system snapshot"
        echo "  restore [name|file]  Restore from snapshot"
        echo "  rollback [target]    Rollback to last/specified snapshot"
        echo ""
        echo "Profiles:"
        echo "  profile-save [name]  Save current config as profile"
        echo "  profile-apply <name> Apply saved profile"
        echo "  profile-list         List available profiles"
        echo ""
        echo "Apps:"
        echo "  apps-sync            Sync local apps catalog"
        echo "  apps-export [file]   Export installed apps list"
        echo "  apps-import <file>   Import and install apps"
        echo ""
        echo "History:"
        echo "  history [limit]      Show recovery history"
        echo "  catalog              Show full catalog"
        echo ""
        echo "Reborn:"
        echo "  reborn [output]      Generate self-contained reborn script"
        ;;
esac
