#!/usr/bin/env bash
# Copyright 2024 The Hush Developers
# Copyright 2024 The DragonX Developers
# Released under the GPLv3
#
# Download and apply a DRAGONX blockchain bootstrap.
# Safely preserves wallet.dat and configuration files.

set -euo pipefail

BOOTSTRAP_BASE_URL="https://bootstrap.dragonx.is"
BOOTSTRAP_FALLBACK_URL="https://bootstrap2.dragonx.is"
BOOTSTRAP_FILE="DRAGONX.zip"
CHAIN_NAME="DRAGONX"

# DragonX bootstrap signing public key (PEM, openssl-compatible).
# WHY: the .md5/.sha256 files are served from the same host as the archive, so they
# only detect transmission corruption — a compromised bootstrap server could publish a
# malicious archive with matching checksums. A detached signature verified against THIS
# embedded public key (shipped in the repo, not downloaded) closes that gap: a bad server
# cannot forge a signature without the maintainer's offline private key.
#
# ROLLOUT: until the maintainer embeds a real key here and publishes DRAGONX.zip.sig,
# this stays as the placeholder and signature enforcement is skipped (with a loud warning),
# so existing users are unaffected. Once a real key is pasted in, an unsigned/invalid
# bootstrap is refused (fail-closed). See util/sign-bootstrap.md for the signing procedure.
BOOTSTRAP_PUBKEY_PLACEHOLDER="REPLACE_WITH_DRAGONX_BOOTSTRAP_PUBLIC_KEY_PEM"
BOOTSTRAP_PUBKEY="$BOOTSTRAP_PUBKEY_PLACEHOLDER"

# Determine data directory
if [[ "$OSTYPE" == "darwin"* ]]; then
    DATADIR="$HOME/Library/Application Support/Hush/$CHAIN_NAME"
else
    DATADIR="$HOME/.hush/$CHAIN_NAME"
fi

CLI="dragonx-cli"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

info()  { echo -e "${GREEN}[INFO]${NC} $*" >&2; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $*" >&2; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }

# Find dragonx-cli in PATH or relative to this script
find_cli() {
    if command -v "$CLI" &>/dev/null; then
        CLI=$(command -v "$CLI")
    elif [[ -x "$(dirname "$0")/../../src/$CLI" ]]; then
        CLI="$(dirname "$0")/../../src/$CLI"
    else
        CLI=""
    fi
}

# Stop the daemon if running
stop_daemon() {
    find_cli
    if [[ -n "$CLI" ]]; then
        if "$CLI" getinfo &>/dev/null 2>&1; then
            info "Stopping DragonX daemon..."
            "$CLI" stop 2>/dev/null || true
            # Wait for daemon to exit
            local tries=0
            while "$CLI" getinfo &>/dev/null 2>&1; do
                sleep 2
                tries=$((tries + 1))
                if [[ $tries -ge 60 ]]; then
                    error "Daemon did not stop after 120 seconds. Please stop it manually and retry."
                fi
            done
            info "Daemon stopped."
        else
            info "Daemon is not running."
        fi
    else
        warn "dragonx-cli not found. Please make sure the daemon is stopped before continuing."
        read -rp "Is the DragonX daemon stopped? (y/N): " answer
        if [[ "${answer,,}" != "y" ]]; then
            error "Please stop the daemon first and run this script again."
        fi
    fi
}



# Files/dirs to preserve (never delete these)
PRESERVE_LIST=(
    "wallet.dat"
    "DRAGONX.conf"
    "peers.dat"
)

# Remove blockchain data while preserving wallet and config
clean_chain_data() {
    if [[ ! -d "$DATADIR" ]]; then
        info "Data directory does not exist yet, creating it."
        mkdir -p "$DATADIR"
        return
    fi

    info "Cleaning blockchain data from $DATADIR ..."

    # Move preserved files to a temp location
    local tmpdir
    tmpdir=$(mktemp -d)
    for f in "${PRESERVE_LIST[@]}"; do
        if [[ -e "$DATADIR/$f" ]]; then
            cp -a "$DATADIR/$f" "$tmpdir/"
        fi
    done

    # Remove blockchain directories
    local dirs_to_remove=("blocks" "chainstate" "notarizations" "komodo" "db.log" "debug.log" "fee_estimates.dat" "banlist.dat")
    for d in "${dirs_to_remove[@]}"; do
        if [[ -e "$DATADIR/$d" ]]; then
            rm -rf "$DATADIR/$d"
        fi
    done

    # Restore preserved files
    for f in "${PRESERVE_LIST[@]}"; do
        if [[ -e "$tmpdir/$f" ]]; then
            cp -a "$tmpdir/$f" "$DATADIR/"
        fi
    done
    rm -rf "$tmpdir"

    info "Blockchain data cleaned."
}

# Download a file via wget or curl (returns non-zero on failure)
download_file() {
    local url="$1"
    local outfile="$2"

    if command -v wget &>/dev/null; then
        wget --progress=bar:force -O "$outfile" "$url"
    elif command -v curl &>/dev/null; then
        curl -L --progress-bar -o "$outfile" "$url"
    else
        error "Neither wget nor curl found. Please install one and retry."
    fi
}

# Try downloading from a given base URL; returns non-zero on failure
download_from() {
    local base_url="$1"
    local outfile="$DATADIR/$BOOTSTRAP_FILE"
    local md5file="$DATADIR/${BOOTSTRAP_FILE}.md5"
    local sha256file="$DATADIR/${BOOTSTRAP_FILE}.sha256"
    local sigfile="$DATADIR/${BOOTSTRAP_FILE}.sig"

    info "Downloading bootstrap from $base_url ..."
    info "This may take a while depending on your connection speed."

    download_file "$base_url/$BOOTSTRAP_FILE" "$outfile" || return 1
    info "Bootstrap download complete."

    info "Downloading checksums..."
    download_file "$base_url/${BOOTSTRAP_FILE}.md5" "$md5file" || return 1
    download_file "$base_url/${BOOTSTRAP_FILE}.sha256" "$sha256file" || return 1
    # Detached signature is optional during rollout (non-fatal if absent); enforcement
    # is decided in verify_signature() based on whether a real public key is embedded.
    rm -f "$sigfile"
    download_file "$base_url/${BOOTSTRAP_FILE}.sig" "$sigfile" || warn "No signature file at $base_url (${BOOTSTRAP_FILE}.sig)"
    return 0
}

# Verify the detached signature of the archive against the embedded release public key.
# Fail-closed once a real key is configured; skip (with warning) while the placeholder is in place.
verify_signature() {
    local archive="$1"
    local sigfile="$2"

    if [[ "$BOOTSTRAP_PUBKEY" == "$BOOTSTRAP_PUBKEY_PLACEHOLDER" ]]; then
        warn "Bootstrap signature verification is not yet configured (no maintainer key embedded)."
        warn "Relying on TLS + checksum integrity only. See util/sign-bootstrap.md."
        return 0
    fi

    if ! command -v openssl &>/dev/null; then
        error "openssl is required to verify the bootstrap signature but was not found. Install openssl and retry."
    fi
    if [[ ! -s "$sigfile" ]]; then
        error "Bootstrap signature (${BOOTSTRAP_FILE}.sig) is missing; refusing to use an unsigned bootstrap."
    fi

    local pubfile
    pubfile=$(mktemp)
    printf '%s\n' "$BOOTSTRAP_PUBKEY" > "$pubfile"
    if openssl dgst -sha256 -verify "$pubfile" -signature "$sigfile" "$archive" >&2; then
        rm -f "$pubfile"
        info "Bootstrap signature verified against embedded DragonX release key."
    else
        rm -f "$pubfile"
        error "Bootstrap signature verification FAILED — the archive is NOT signed by the DragonX release key. Aborting; do not use this bootstrap."
    fi
}

# Download the bootstrap and verify checksums
download_bootstrap() {
    local outfile="$DATADIR/$BOOTSTRAP_FILE"
    local md5file="$DATADIR/${BOOTSTRAP_FILE}.md5"
    local sha256file="$DATADIR/${BOOTSTRAP_FILE}.sha256"
    local sigfile="$DATADIR/${BOOTSTRAP_FILE}.sig"

    if ! download_from "$BOOTSTRAP_BASE_URL"; then
        warn "Primary download failed, trying fallback $BOOTSTRAP_FALLBACK_URL ..."
        download_from "$BOOTSTRAP_FALLBACK_URL" || error "Download failed from both primary and fallback servers."
    fi

    # Verify checksums
    info "Verifying checksums..."
    cd "$DATADIR"

    if command -v md5sum &>/dev/null; then
        if md5sum -c "$md5file" >&2; then
            info "MD5 checksum verified."
        else
            error "MD5 checksum verification failed! The download may be corrupted."
        fi
    else
        warn "md5sum not found, skipping MD5 verification."
    fi

    if command -v sha256sum &>/dev/null; then
        if sha256sum -c "$sha256file" >&2; then
            info "SHA256 checksum verified."
        else
            error "SHA256 checksum verification failed! The download may be corrupted."
        fi
    else
        warn "sha256sum not found, skipping SHA256 verification."
    fi

    # Verify the cryptographic signature (fail-closed once a release key is embedded).
    verify_signature "$outfile" "$sigfile"

    # Clean up checksum + signature files
    rm -f "$md5file" "$sha256file" "$sigfile"

    echo "$outfile"
}

# Extract the bootstrap
extract_bootstrap() {
    local archive="$1"

    info "Extracting bootstrap..."
    cd "$DATADIR"

    # Extract zip, but never overwrite wallet.dat or config
    unzip -o "$archive" -x 'wallet.dat' '*.conf' || error "Extraction failed. Please install unzip and retry."

    info "Bootstrap extracted successfully."

    # Clean up the downloaded archive
    rm -f "$archive"
    info "Removed downloaded archive to save disk space."
}



main() {
    echo "============================================"
    echo "  DragonX Bootstrap Installer"
    echo "============================================"
    echo ""
    info "Data directory: $DATADIR"
    echo ""

    # Step 1: Stop daemon
    stop_daemon

    # Step 2: Clean old chain data
    clean_chain_data

    # Step 3: Download bootstrap
    local archive
    archive=$(download_bootstrap)

    # Step 4: Extract bootstrap
    extract_bootstrap "$archive"

    echo ""
    info "Bootstrap installation complete!"
    info "You can now start DragonX with: dragonxd"
    echo ""
}

main "$@"
