#!/bin/bash

# Copyright 2026 Joe Harris / BenchBox Project. Licensed under the MIT License.

# Compile TPC binaries for multiple platforms using Docker
# This script implements the research findings for TPC-DS compilation fixes

set -euo pipefail

# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"

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

# Logging functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Platform configurations for all supported targets
PLATFORMS=(
    "darwin:arm64:native"
    "darwin:x86_64:cross"
    "linux:x86_64:docker"
    "linux:arm64:docker"
    "windows:x86_64:docker"
    "windows:arm64:docker"
)

# Function to compile TPC-H for macOS ARM64 natively
compile_tpch_macos_native() {
    log_info "Compiling TPC-H natively for macOS ARM64..."

    local platform_dir="$PROJECT_ROOT/_binaries/tpc-h/darwin-arm64"
    local temp_build="/tmp/tpch-build-native-$$"

    # Create temporary build directory
    mkdir -p "$temp_build"
    cp -r "$PROJECT_ROOT/_sources/tpc-h/dbgen"/* "$temp_build/"

    # Build using native macOS clang
    cd "$temp_build"
    make -f makefile.suite clean || true
    make -f makefile.suite CC=clang MACHINE=LINUX DATABASE=ORACLE WORKLOAD=TPCH

    # Copy binaries and required files
    cp dbgen qgen dists.dss "$platform_dir/"

    # Generate checksums
    cd "$platform_dir"
    if command -v md5 >/dev/null 2>&1; then
        md5 -r dbgen qgen dists.dss > checksums.md5
    else
        md5sum dbgen qgen dists.dss > checksums.md5
    fi

    # Cleanup
    rm -rf "$temp_build"

    log_success "TPC-H native macOS ARM64 compilation completed"
}

# Function to compile TPC-DS for macOS ARM64 natively
compile_tpcds_macos_native() {
    log_info "Compiling TPC-DS natively for macOS ARM64..."

    local platform_dir="$PROJECT_ROOT/_binaries/tpc-ds/darwin-arm64"
    local temp_build="/tmp/tpcds-build-native-$$"

    # Create temporary build directory
    mkdir -p "$temp_build"
    cp -r "$PROJECT_ROOT/_sources/tpc-ds/tools"/* "$temp_build/"

    # Apply TPC-DS fixes for macOS
    cd "$temp_build"

    # Fix MAXINT issue by ensuring proper includes
    if ! grep -q "#include <limits.h>" genrand.c; then
        sed -i '' '1i\
#include <limits.h>
' genrand.c
    fi

    # Build using native macOS clang
    make clean || true

    # First build distcomp and generate tpcds.idx
    make CC=clang distcomp CFLAGS="-O2 -DMACOS -DMAXINT=INT_MAX -fcommon" LDFLAGS=""
    ./distcomp -i tpcds.dst -o tpcds.idx

    # Now build the main tools
    make CC=clang dsdgen dsqgen CFLAGS="-O2 -DMACOS -DMAXINT=INT_MAX -fcommon" LDFLAGS=""

    # Copy binaries and required files
    cp dsdgen dsqgen tpcds.dst tpcds.idx "$platform_dir/"
    cp -r "$PROJECT_ROOT/_sources/tpc-ds/query_templates" "$platform_dir/"

    # Generate checksums
    cd "$platform_dir"
    find . -type f -name "*.dst" -o -name "*.idx" -o -name "*gen" | xargs md5 -r > checksums.md5

    # Cleanup
    rm -rf "$temp_build"

    log_success "TPC-DS native macOS ARM64 compilation completed"
}

# Function to compile TPC-H for macOS with cross-compilation
compile_tpch_macos_cross() {
    local target_arch="$1"
    log_info "Cross-compiling TPC-H for macOS ${target_arch}..."

    local platform_dir="$PROJECT_ROOT/_binaries/tpc-h/darwin-${target_arch}"
    mkdir -p "$platform_dir"

    # Create temporary build directory
    local build_dir="/tmp/tpch-cross-${target_arch}-$$"
    rm -rf "$build_dir"
    cp -r "$PROJECT_ROOT/_sources/tpc-h/dbgen" "$build_dir"

    cd "$build_dir"

    # Set cross-compilation flags
    local cross_flags=""
    if [ "$target_arch" = "x86_64" ]; then
        cross_flags="-arch x86_64"
    fi

    # Clean and compile
    make -f makefile.suite clean || true
    make -f makefile.suite \
        CC="clang $cross_flags" \
        MACHINE=LINUX \
        DATABASE=ORACLE \
        WORKLOAD=TPCH \
        CFLAGS="-g -DDBNAME=\\\"dss\\\" -DLINUX -DORACLE -DTPCH -DRNG_TEST -D_FILE_OFFSET_BITS=64" \
        LDFLAGS="$cross_flags -O" \
        || {
            log_error "TPC-H cross-compilation failed for macOS ${target_arch}"
            rm -rf "$build_dir"
            return 1
        }

    # Copy binaries and required files
    cp dbgen qgen dists.dss "$platform_dir/"
    chmod +x "$platform_dir/dbgen" "$platform_dir/qgen"

    # Generate checksums
    cd "$platform_dir"
    md5 * > checksums.md5

    # Clean up
    rm -rf "$build_dir"

    log_success "TPC-H cross-compilation completed for macOS ${target_arch}"
}

# Function to compile TPC-DS for macOS with cross-compilation
compile_tpcds_macos_cross() {
    local target_arch="$1"
    log_info "Cross-compiling TPC-DS for macOS ${target_arch}..."

    local platform_dir="$PROJECT_ROOT/_binaries/tpc-ds/darwin-${target_arch}"
    mkdir -p "$platform_dir"

    # Create temporary build directory
    local build_dir="/tmp/tpcds-cross-${target_arch}-$$"
    rm -rf "$build_dir"
    cp -r "$PROJECT_ROOT/_sources/tpc-ds/tools" "$build_dir"

    cd "$build_dir"

    # Set cross-compilation flags
    local cross_flags=""
    if [ "$target_arch" = "x86_64" ]; then
        cross_flags="-arch x86_64"
    fi

    # Apply TPC-DS fixes
    sed -i '' '1i\
#include <limits.h>
' genrand.c

    # Clean and compile
    make clean || true

    # First build distcomp and generate tpcds.idx
    make distcomp \
        CC="clang $cross_flags" \
        CFLAGS="-O2 -DMACOS -DMAXINT=INT_MAX -fcommon $cross_flags" \
        LDFLAGS="$cross_flags" \
        || {
            log_error "TPC-DS distcomp cross-compilation failed for macOS ${target_arch}"
            rm -rf "$build_dir"
            return 1
        }

    ./distcomp -i tpcds.dst -o tpcds.idx

    # Now build the main tools
    make dsdgen dsqgen \
        CC="clang $cross_flags" \
        CFLAGS="-O2 -DMACOS -DMAXINT=INT_MAX -fcommon $cross_flags" \
        LDFLAGS="$cross_flags" \
        || {
            log_error "TPC-DS cross-compilation failed for macOS ${target_arch}"
            rm -rf "$build_dir"
            return 1
        }

    # Copy binaries and required files
    cp dsdgen dsqgen tpcds.dst tpcds.idx "$platform_dir/"
    cp -r "$PROJECT_ROOT/_sources/tpc-ds/query_templates" "$platform_dir/"
    chmod +x "$platform_dir/dsdgen" "$platform_dir/dsqgen"

    # Generate checksums
    cd "$platform_dir"
    find . -type f -name '*.dst' -o -name '*.idx' -o -name '*gen' | xargs md5 > checksums.md5

    # Clean up
    rm -rf "$build_dir"

    log_success "TPC-DS cross-compilation completed for macOS ${target_arch}"
}

# Function to compile binaries using Docker
compile_with_docker() {
    local platform=$1
    local arch=$2
    local benchmark=$3  # tpc-h or tpc-ds

    local benchmark_upper=$(echo "$benchmark" | tr '[:lower:]' '[:upper:]')
    log_info "Compiling ${benchmark_upper} for ${platform}-${arch} using Docker..."

    local platform_dir="$PROJECT_ROOT/_binaries/${benchmark}/${platform}-${arch}"
    local docker_platform="linux/${arch}"

    # Build Docker image
    local image_name="benchbox/${benchmark}-${platform}-${arch}"
    docker build -f "$PROJECT_ROOT/_sources/compilation/docker/Dockerfile.${platform}-${arch}" \
                 -t "$image_name" \
                 "$PROJECT_ROOT/_sources/compilation/docker/"

    if [ "$benchmark" = "tpc-h" ]; then
        compile_tpch_docker "$platform" "$arch" "$image_name" "$platform_dir"
    else
        compile_tpcds_docker "$platform" "$arch" "$image_name" "$platform_dir"
    fi
}

# Function to compile TPC-H using Docker
compile_tpch_docker() {
    local platform=$1
    local arch=$2
    local image_name=$3
    local platform_dir=$4

    docker run --rm \
        -v "$PROJECT_ROOT/_sources/tpc-h/dbgen:/build/source" \
        -v "$platform_dir:/build/output" \
        "$image_name" \
        bash -c "
            cd /build/source
            make -f makefile.suite clean || true

            # Set compilation parameters based on platform
            if [ '$platform' = 'windows' ]; then
                # Fix MinGW integer literal compatibility in config.h
                sed -i 's/6364136223846793005uI64/6364136223846793005ULL/g' config.h
                sed -i 's/1uI64/1ULL/g' config.h

                # Windows cross-compilation with MinGW
                make -f makefile.suite CC=\$CROSS_CC MACHINE=\$CROSS_MACHINE DATABASE=\$CROSS_DATABASE WORKLOAD=\$CROSS_WORKLOAD
                cp dbgen.exe qgen.exe dists.dss /build/output/ || cp dbgen qgen dists.dss /build/output/
            else
                # Linux compilation
                make -f makefile.suite CC=gcc MACHINE=LINUX DATABASE=ORACLE WORKLOAD=TPCH
                cp dbgen qgen dists.dss /build/output/
            fi

            cd /build/output
            md5sum * > checksums.md5 2>/dev/null || true
        "

    log_success "TPC-H Docker compilation completed for ${platform}-${arch}"
}

# Function to compile TPC-DS using Docker with fixes
compile_tpcds_docker() {
    local platform=$1
    local arch=$2
    local image_name=$3
    local platform_dir=$4

    docker run --rm \
        -v "$PROJECT_ROOT/_sources/tpc-ds/tools:/build/source" \
        -v "$PROJECT_ROOT/_sources/tpc-ds/query_templates:/build/query_templates" \
        -v "$platform_dir:/build/output" \
        "$image_name" \
        bash -c "
            cd /build/source

            # Apply TPC-DS compilation fixes based on research
            # Fix 1: Add limits.h include for MAXINT
            if ! grep -q '#include <limits.h>' genrand.c; then
                sed -i '1i#include <limits.h>' genrand.c
            fi

            # Set compilation parameters based on platform
            make clean || true
            if [ '$platform' = 'windows' ]; then
                # Start Xvfb for Wine headless operation
                Xvfb :99 -screen 0 1024x768x16 &
                XVFB_PID=\$!

                # Initialize Wine prefix for cross-compilation
                wineboot --init 2>/dev/null || true

                # Windows cross-compilation with MinGW and Wine emulation for build tools
                # First, build mkheader and run it with Wine
                make CC=\$CROSS_CC mkheader.exe CFLAGS='-O2 -DWIN32 -DMAXINT=INT_MAX -fcommon' || \
                make CC=\$CROSS_CC mkheader CFLAGS='-O2 -DWIN32 -DMAXINT=INT_MAX -fcommon'

                # Run mkheader with Wine to generate headers
                if [ -f mkheader.exe ]; then
                    wine mkheader.exe column_list.txt 2>/dev/null || wine mkheader column_list.txt 2>/dev/null
                elif [ -f mkheader ]; then
                    wine mkheader column_list.txt 2>/dev/null
                fi

                # Build distcomp and generate tpcds.idx
                make CC=\$CROSS_CC distcomp CFLAGS='-O2 -DWIN32 -DMAXINT=INT_MAX -fcommon' LDFLAGS='-static'
                wine ./distcomp -i tpcds.dst -o tpcds.idx 2>/dev/null || ./distcomp -i tpcds.dst -o tpcds.idx

                # Now build the main binaries
                make CC=\$CROSS_CC dsdgen dsqgen CFLAGS='-O2 -DWIN32 -DMAXINT=INT_MAX -fcommon' LDFLAGS='-static'

                # Kill Xvfb
                kill \$XVFB_PID 2>/dev/null || true

                cp dsdgen.exe dsqgen.exe tpcds.dst tpcds.idx /build/output/ || cp dsdgen dsqgen tpcds.dst tpcds.idx /build/output/
            else
                # Linux compilation with GCC 9 for TPC-DS compatibility
                # First build distcomp to generate tpcds.idx
                make CC=gcc-9 distcomp CFLAGS='-O2 -DLINUX -DMAXINT=INT_MAX -fcommon' LDFLAGS='-static'
                ./distcomp -i tpcds.dst -o tpcds.idx

                # Now build main tools
                make CC=gcc-9 dsdgen dsqgen CFLAGS='-O2 -DLINUX -DMAXINT=INT_MAX -fcommon' LDFLAGS='-static'
                cp dsdgen dsqgen tpcds.dst tpcds.idx /build/output/
            fi

            # Copy query templates
            cp -r /build/query_templates /build/output/

            # Generate checksums
            cd /build/output
            find . -type f -name '*.dst' -o -name '*.idx' -o -name '*gen' | xargs md5sum > checksums.md5 2>/dev/null || true
        "

    log_success "TPC-DS Docker compilation completed for ${platform}-${arch}"
}

# Function to compile all platforms
compile_all_platforms() {
    log_info "Starting compilation for all target platforms..."

    # Compile for each platform
    for platform_config in "${PLATFORMS[@]}"; do
        IFS=':' read -r platform arch method <<< "$platform_config"

        if [ "$method" = "native" ] && [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
            # Native macOS ARM64 compilation
            compile_tpch_macos_native
            compile_tpcds_macos_native
        elif [ "$method" = "cross" ] && [ "$(uname -s)" = "Darwin" ]; then
            # Cross-compilation on macOS
            compile_tpch_macos_cross "$arch"
            compile_tpcds_macos_cross "$arch"
        elif [ "$method" = "docker" ]; then
            # Docker-based compilation
            compile_with_docker "$platform" "$arch" "tpc-h"
            compile_with_docker "$platform" "$arch" "tpc-ds"
        else
            log_warning "Skipping ${platform}-${arch} (method: ${method}) - not supported on current host"
        fi
    done

    log_success "All platform compilation completed!"
}

# Function to verify all binaries
verify_all_binaries() {
    log_info "Verifying all compiled binaries..."

    local failed_verifications=0
    local total_platforms=0
    local successful_platforms=0

    for platform_config in "${PLATFORMS[@]}"; do
        IFS=':' read -r platform arch method <<< "$platform_config"
        local platform_name="${platform}-${arch}"

        # TPC-H verification
        local tpch_dir="$PROJECT_ROOT/_binaries/tpc-h/${platform_name}"
        if [ -d "$tpch_dir" ] && [ -f "$tpch_dir/checksums.md5" ]; then
            cd "$tpch_dir"
            if md5sum -c checksums.md5 2>/dev/null || md5 -c checksums.md5 2>/dev/null; then
                log_success "TPC-H checksum verification passed for ${platform_name}"
                ((successful_platforms++))
            else
                log_error "TPC-H checksum verification failed for ${platform_name}"
                ((failed_verifications++))
            fi
        else
            log_warning "TPC-H binaries or checksums missing for ${platform_name}"
        fi

        # TPC-DS verification
        local tpcds_dir="$PROJECT_ROOT/_binaries/tpc-ds/${platform_name}"
        if [ -d "$tpcds_dir" ] && [ -f "$tpcds_dir/checksums.md5" ]; then
            cd "$tpcds_dir"
            if md5sum -c checksums.md5 2>/dev/null || md5 -c checksums.md5 2>/dev/null; then
                log_success "TPC-DS checksum verification passed for ${platform_name}"
                ((successful_platforms++))
            else
                log_error "TPC-DS checksum verification failed for ${platform_name}"
                ((failed_verifications++))
            fi
        else
            log_warning "TPC-DS binaries or checksums missing for ${platform_name}"
        fi

        ((total_platforms++))
    done

    if [ $failed_verifications -eq 0 ]; then
        log_success "All binary verifications passed (${successful_platforms} successful)"
        return 0
    else
        log_error "$failed_verifications binary verifications failed"
        return 1
    fi
}

# Function to display compilation summary
display_summary() {
    log_info "=== Compilation Summary ==="

    local total_binaries=0
    local successful_binaries=0

    for platform_config in "${PLATFORMS[@]}"; do
        IFS=':' read -r platform arch method <<< "$platform_config"
        local platform_name="${platform}-${arch}"

        # Check TPC-H
        local tpch_dir="$PROJECT_ROOT/_binaries/tpc-h/${platform_name}"
        if [ -d "$tpch_dir" ] && [ -n "$(ls -A "$tpch_dir" 2>/dev/null)" ]; then
            local tpch_status="${GREEN}✅${NC}"
            ((successful_binaries++))
        else
            local tpch_status="${RED}❌${NC}"
        fi

        # Check TPC-DS
        local tpcds_dir="$PROJECT_ROOT/_binaries/tpc-ds/${platform_name}"
        if [ -d "$tpcds_dir" ] && [ -n "$(ls -A "$tpcds_dir" 2>/dev/null)" ]; then
            local tpcds_status="${GREEN}✅${NC}"
            ((successful_binaries++))
        else
            local tpcds_status="${RED}❌${NC}"
        fi

        printf "  %-20s TPC-H: %b  TPC-DS: %b\n" "$platform_name" "$tpch_status" "$tpcds_status"
        ((total_binaries += 2))
    done

    echo ""
    log_success "Binary compilation completed! ${successful_binaries}/${total_binaries} binaries compiled successfully"
    log_info "Binaries stored in _binaries/ directory structure"
    echo ""
    log_info "Key fixes applied:"
    log_info "  • GCC 9 used for TPC-DS compatibility"
    log_info "  • MAXINT properly defined with limits.h"
    log_info "  • -fcommon flag added for multiple definition issues"
    log_info "  • Native compilation on macOS ARM64"
    log_info "  • Docker-based cross-compilation for Linux platforms"
}

# Main execution
main() {
    log_info "Starting TPC binary compilation with TPC-DS fixes..."

    # Change to project root
    cd "$PROJECT_ROOT"

    # Check Docker availability for Docker-based platforms
    if ! command -v docker &> /dev/null; then
        log_error "Docker is not installed or not available"
        exit 1
    fi

    compile_all_platforms
    verify_all_binaries
    display_summary

    log_success "Build process completed successfully with TPC-DS compilation fixes applied!"
}

# Execute main function
main "$@"