#!/usr/bin/bash

# binary file usage:
#   bin/mysql-rest-$(uname -m) -r 0.0.0.0 --dialect dameng -n 15236 -h 127.0.0.1 -o 5236 -u SYSDBA -p voYjiYxof8W68kN73DuphVzep2tk2eZf6FsXPZJF

#   bin/mysql-rest-$(uname -m) -r 0.0.0.0 -n 15000 -h 127.0.0.1 -o 33306 -u root -p ElksuYon50WGde3Vth290IhraXvySjg8agULIINh

# dmdb depends on 'snappy', while the 'snappy' only support to node18
# see: https://www.npmjs.com/package/snappy
# using node16 to avoid 'export NODE_OPTIONS=--openssl-legacy-provider'

if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    echo "Usage examples:"
    echo "  ./pkg.sh                                   # Build both architectures with default Node.js"
    echo "  ARCH=x86_64 ./pkg.sh                       # Build x86_64 only with default Node.js"
    echo "  NODE_VERSION_X86=v22.17.0 NODE_VERSION_ARM=v20.11.1 ./pkg.sh  # Different versions per arch"
    echo "  NODE_VERSION_X86=v20.11.1 ./pkg.sh         # x86_64 with v20.11.1, aarch64 with default"
    echo "  NODE_VERSION_ARM=v18.19.1 ./pkg.sh         # aarch64 with v18.19.1, x86_64 with default"
    exit 0
fi

get_node_version_for_arch() {
    local arch="$1"
    local version

    if [ "$arch" = "x86_64" ] && [ -n "$NODE_VERSION_X86" ]; then
        version="$NODE_VERSION_X86"
    elif [ "$arch" = "aarch64" ] && [ -n "$NODE_VERSION_ARM" ]; then
        version="$NODE_VERSION_ARM"
    elif [ "$arch" = "x86_64" ]; then
        version="v22.17.0"
    else
        version="v16.20.2"
    fi

    echo "$version"
}

build_for_arch() {
    local arch="$1"
    local node_version=$(get_node_version_for_arch "$arch")

    echo "Building for architecture: $arch with Node.js $node_version"

    if [ "$arch" != "x86_64" ] && [ "$arch" != "aarch64" ]; then
        echo "Error: Unsupported architecture '$arch'. Supported: x86_64, aarch64"
        return 1
    fi

    local output_file="bin/mysql-rest-$arch"

    rm -f "$output_file"

    local node_modules_archive
    if [ "$arch" = "aarch64" ]; then
        node_modules_archive="node_modules-aarch64.tar.gz"
    elif [ "$arch" = "x86_64" ]; then
        node_modules_archive="node_modules-x86_64.tar.gz"
    fi

    if [ ! -f "$node_modules_archive" ]; then
        echo "Error: Required node_modules archive not found: $node_modules_archive"
        echo "Please ensure you have the node_modules archive for target architecture."
        return 1
    fi

    echo "Using node_modules archive: $node_modules_archive"

    local node_binary_dir="$HOME/.cache/node-binaries"
    mkdir -p "$node_binary_dir"

    local node_binary_file
    local node_download_url
    if [ "$arch" = "aarch64" ]; then
        node_binary_file="$node_binary_dir/node-$node_version-linux-arm64"
        node_download_url="https://nodejs.org/dist/$node_version/node-$node_version-linux-arm64.tar.gz"
    elif [ "$arch" = "x86_64" ]; then
        node_binary_file="$node_binary_dir/node-$node_version-linux-x64"
        node_download_url="https://nodejs.org/dist/$node_version/node-$node_version-linux-x64.tar.gz"
    fi

    if [ ! -f "$node_binary_file" ]; then
        echo "Downloading Node.js $node_version binary for $arch..."
        local temp_node_archive="/tmp/node-$node_version-$arch.tar.gz"

        if [ -f "$temp_node_archive" ]; then
            echo "Using cached Node.js archive: $temp_node_archive"
        else
            echo "Downloading from: $node_download_url"
            if command -v wget >/dev/null 2>&1; then
                wget -q "$node_download_url" -O "$temp_node_archive"
            elif command -v curl >/dev/null 2>&1; then
                curl -s -L "$node_download_url" -o "$temp_node_archive"
            else
                echo "Error: Neither wget nor curl found. Cannot download Node.js binary."
                echo "Please manually download Node.js binary for $arch and place it at: $node_binary_file"
                return 1
            fi
        fi

        if [ ! -f "$temp_node_archive" ]; then
            echo "Error: Failed to download Node.js binary"
            return 1
        fi

        local temp_extract_dir="/tmp/node-extract-$$-$arch"
        mkdir -p "$temp_extract_dir"
        tar xzf "$temp_node_archive" -C "$temp_extract_dir" --strip-components=1

        if [ -f "$temp_extract_dir/bin/node" ]; then
            cp "$temp_extract_dir/bin/node" "$node_binary_file"
            chmod +x "$node_binary_file"
            echo "Node.js $node_version binary downloaded and saved to: $node_binary_file"
        else
            echo "Error: Could not extract Node.js binary"
            rm -rf "$temp_extract_dir"
            return 1
        fi

        rm -rf "$temp_extract_dir"
    else
        echo "Using existing Node.js $node_version binary: $node_binary_file"
    fi

    echo "removing node_modules..."
    rm -rf node_modules
    echo "extracting $node_modules_archive..."
    tar xzf "$node_modules_archive"

    echo "Building self-contained application for $arch..."

    cat >$output_file <<EOF
#!/bin/bash

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

# Generate a hash of this binary for consistent directory naming
BINARY_HASH=\$(head -c 1024 "\$0" | sha256sum | cut -d' ' -f1 | cut -c1-8)
TEMP_DIR="/tmp/mysql-rest-\$BINARY_HASH"
ARCHIVE_LINE=\$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "\$0")
LOCK_FILE="\$TEMP_DIR.lock"

cleanup_old_dirs() {
    # Clean up old mysql-rest directories (older than 1 day) but keep current one
    find /tmp -maxdepth 1 -name "mysql-rest-*" -type d -mtime +1 ! -name "mysql-rest-\$BINARY_HASH" -exec rm -rf {} \; 2>/dev/null || true
    find /tmp -maxdepth 1 -name "mysql-rest-*.lock" -mtime +1 ! -name "mysql-rest-\$BINARY_HASH.lock" -exec rm -f {} \; 2>/dev/null || true
}

# Check if extraction is needed
extract_if_needed() {
    # If directory exists and is complete, use it
    if [ -d "\$TEMP_DIR" ] && [ -f "\$TEMP_DIR/node" ] && [ -f "\$TEMP_DIR/bin/index.js" ] && [ -d "\$TEMP_DIR/node_modules" ]; then
        return 0
    fi
    
    # Use flock for atomic extraction to prevent race conditions
    if command -v flock >/dev/null 2>&1; then
        (
            flock -n 200 || {
                # If lock fails, wait for extraction to complete
                while [ ! -d "\$TEMP_DIR" ] || [ ! -f "\$TEMP_DIR/node" ]; do
                    sleep 0.1
                done
                return 0
            }
            
            # Double-check after acquiring lock
            if [ -d "\$TEMP_DIR" ] && [ -f "\$TEMP_DIR/node" ] && [ -f "\$TEMP_DIR/bin/index.js" ] && [ -d "\$TEMP_DIR/node_modules" ]; then
                return 0
            fi
            
            # Extract the archive
            rm -rf "\$TEMP_DIR"
            mkdir -p "\$TEMP_DIR"
            tail -n +\$ARCHIVE_LINE "\$0" | tar xzf - -C "\$TEMP_DIR" 2>/dev/null
            
        ) 200>"\$LOCK_FILE"
    else
        # Fallback without flock
        if [ ! -d "\$TEMP_DIR" ]; then
            mkdir -p "\$TEMP_DIR"
            tail -n +\$ARCHIVE_LINE "\$0" | tar xzf - -C "\$TEMP_DIR" 2>/dev/null
        fi
    fi
}

# Clean up old directories on startup
cleanup_old_dirs

# Extract if needed
extract_if_needed

if [ ! -d "\$TEMP_DIR/node_modules" ] || [ ! -f "\$TEMP_DIR/bin/index.js" ] || [ ! -f "\$TEMP_DIR/node" ]; then
    echo "Error: Failed to extract application files"
    exit 1
fi

export NODE_PATH="\$TEMP_DIR/node_modules:\$NODE_PATH"

cd "\$TEMP_DIR"
exec ./node bin/index.js "\$@"

exit \$?

__ARCHIVE_BELOW__
EOF

    echo "Creating application archive..."

    cp "$node_binary_file" "./node"

    # Create deterministic tar archive for consistent MD5 hashes
    # --sort=name: ensures consistent file ordering
    # --mtime='1970-01-01': sets all timestamps to epoch (deterministic)
    # --owner=0 --group=0: consistent ownership
    # --numeric-owner: avoid username/groupname dependencies
    tar czf - \
        --exclude="bin/mysql-rest-*" \
        --sort=name \
        --mtime='1970-01-01' \
        --owner=0 \
        --group=0 \
        --numeric-owner \
        bin lib node_modules package.json node >>"$output_file"

    rm -f "./node"

    chmod a+x $output_file

    echo "✓ Self-contained application created successfully: $output_file"
    return 0
}

if [ -n "$NODE_VERSION_X86" ]; then
    echo "Using Node.js version for x86_64: $NODE_VERSION_X86"
fi
if [ -n "$NODE_VERSION_ARM" ]; then
    echo "Using Node.js version for aarch64: $NODE_VERSION_ARM"
fi
if [ -z "$NODE_VERSION_X86" ] && [ -z "$NODE_VERSION_ARM" ]; then
    echo "Using default Node.js versions: x86_64=v22.17.0, aarch64=v16.20.2 (set NODE_VERSION_X86 or NODE_VERSION_ARM to override)"
fi

if [ -n "$ARCH" ]; then
    echo "Building for specified architecture: $ARCH"
    architectures="$ARCH"
else
    echo "Building for both x86_64 and aarch64 architectures"
    architectures="x86_64 aarch64"
fi

echo ""

build_success=0
build_count=0
failed_builds=""

for arch in $architectures; do
    echo "========================================"
    if build_for_arch "$arch"; then
        build_success=$((build_success + 1))
    else
        failed_builds="$failed_builds $arch"
    fi
    build_count=$((build_count + 1))
    echo ""
done

if [ "$build_success" -gt 0 ]; then
    # Cleanup any leftover temporary directories
    echo "========================================"
    echo "Cleaning up temporary directories..."
    TEMP_DIRS=$(find /tmp -maxdepth 1 -name "mysql-rest-*" -type d 2>/dev/null)
    TEMP_COUNT=$(echo "$TEMP_DIRS" | grep -c "mysql-rest-" 2>/dev/null || echo "0")

    # Handle case where TEMP_DIRS is empty (grep returns empty with newlines)
    if [ -z "$TEMP_DIRS" ] || [ "$TEMP_DIRS" = "" ]; then
        TEMP_COUNT=0
    fi

    if [ "$TEMP_COUNT" -gt 0 ]; then
        echo "Found $TEMP_COUNT mysql-rest temporary directories to clean up:"
        echo "$TEMP_DIRS"

        # Show disk usage
        TOTAL_SIZE=$(du -sh /tmp/mysql-rest-* 2>/dev/null | awk '{sum += $1} END {print sum "M"}' || echo "0M")
        echo "Total disk usage: $TOTAL_SIZE"

        # Remove directories automatically (no user confirmation needed)
        echo "Removing mysql-rest temporary directories..."
        find /tmp -maxdepth 1 -name "mysql-rest-*" -type d -exec rm -rf {} \; 2>/dev/null

        # Verify cleanup
        REMAINING=$(find /tmp -maxdepth 1 -name "mysql-rest-*" -type d 2>/dev/null | wc -l)
        if [ "$REMAINING" -eq 0 ]; then
            echo "✓ All mysql-rest temporary directories have been removed."
        else
            echo "⚠ Warning: $REMAINING directories could not be removed (may be in use)"
        fi
    else
        echo "No mysql-rest temporary directories found in /tmp"
    fi

    echo "Build and cleanup completed successfully!"
    echo ""

    chmod 777 bin/mysql-rest*
    ls -lh bin/mysql-rest*
    file bin/mysql-rest-*
    md5sum bin/mysql-rest-*
else
    echo "Build failed! No executables were created."
    exit 1
fi
