#!/bin/bash
# Configure script for slq - Storstockholms Lokaltrafik Query Tool
# Checks dependencies and sets up build environment

set -euo pipefail

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

# Configuration variables
# Default values
PREFIX="/usr/local"
DEBUG=false
ENABLE_SANITIZERS=false
ENABLE_STATIC=false
CC="cc"
VERBOSE=false
AUTO_INSTALL=true

# Dependency status
DEPS_OK=true
JANSSON_OK=false
CURL_OK=false
PKG_CONFIG_OK=false

# Functions for output
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

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

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

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

log_header() {
    echo -e "\n${BOLD}$1${NC}"
    echo "$(echo "$1" | sed 's/./=/g')"
}

show_usage() {
    cat << EOF
Usage: ./configure [OPTIONS]

Configure slq build environment and check dependencies.

OPTIONS:
    --prefix=DIR         Installation prefix (default: /usr/local)
    --enable-debug       Build with debug symbols and debugging info
    --enable-sanitizers  Build with AddressSanitizer and UBSan (development)
    --enable-static      Build static binary (experimental)
    --cc=COMPILER        Use specific C compiler (default: cc)
    --verbose           Show detailed output
    --no-auto-install   Don't automatically install missing dependencies
    --help              Show this help message

EXAMPLES:
    ./configure                           # Standard configuration (auto-installs dependencies)
    ./configure --no-auto-install        # Check dependencies without installing
    ./configure --prefix=/usr             # Install to /usr instead of /usr/local
    ./configure --enable-debug            # Debug build
    ./configure --enable-sanitizers       # Development build with sanitizers
    ./configure --cc=clang                # Use clang compiler

After running configure, build with:
    make
    make install

For development:
    ./configure --enable-debug --enable-sanitizers
    make test-all

EOF
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            --prefix=*)
                PREFIX="${1#*=}"
                shift
                ;;
            --enable-debug)
                DEBUG=true
                shift
                ;;
            --enable-sanitizers)
                ENABLE_SANITIZERS=true
                shift
                ;;
            --enable-static)
                ENABLE_STATIC=true
                shift
                ;;
            --cc=*)
                CC="${1#*=}"
                shift
                ;;
            --verbose)
                VERBOSE=true
                shift
                ;;
            --no-auto-install)
                AUTO_INSTALL=false
                shift
                ;;
            --help)
                show_usage
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                echo "Use --help for usage information."
                exit 1
                ;;
        esac
    done
}

# Check if a command exists
command_exists() {
    command -v "$1" &> /dev/null
}

# Detect operating system
detect_os() {
    if [[ "$OSTYPE" == "darwin"* ]]; then
        echo "macos"
    elif [[ -f /etc/redhat-release ]]; then
        echo "redhat"
    elif [[ -f /etc/debian_version ]]; then
        echo "debian"
    elif [[ -f /etc/arch-release ]]; then
        echo "arch"
    else
        echo "unknown"
    fi
}

# Install package using system package manager
install_package() {
    local packages="$1"
    local os=$(detect_os)

    case $os in
        macos)
            if ! command_exists brew; then
                log_error "Homebrew not found. Install from https://brew.sh"
                return 1
            fi
            log_info "Installing with Homebrew: $packages"
            brew install $packages
            ;;
        debian)
            log_info "Installing with apt: $packages"
            sudo apt-get update
            sudo apt-get install -y $packages
            ;;
        redhat)
            if command_exists dnf; then
                log_info "Installing with dnf: $packages"
                sudo dnf install -y $packages
            elif command_exists yum; then
                log_info "Installing with yum: $packages"
                sudo yum install -y $packages
            else
                log_error "No package manager found (dnf/yum)"
                return 1
            fi
            ;;
        arch)
            log_info "Installing with pacman: $packages"
            sudo pacman -S --noconfirm $packages
            ;;
        *)
            log_error "Unsupported operating system for auto-install"
            return 1
            ;;
    esac
}

# Get package names for current OS
get_package_names() {
    local dep="$1"
    local os=$(detect_os)

    case "$dep:$os" in
        "pkg-config:macos") echo "pkg-config" ;;
        "pkg-config:debian") echo "pkg-config" ;;
        "pkg-config:redhat") echo "pkgconfig" ;;
        "pkg-config:arch") echo "pkg-config" ;;
        "jansson:macos") echo "jansson" ;;
        "jansson:debian") echo "libjansson-dev" ;;
        "jansson:redhat") echo "jansson-devel" ;;
        "jansson:arch") echo "jansson" ;;
        "curl:macos") echo "curl" ;;
        "curl:debian") echo "libcurl4-openssl-dev" ;;
        "curl:redhat") echo "libcurl-devel" ;;
        "curl:arch") echo "curl" ;;
        "build-tools:macos") echo "" ;; # Xcode tools handled separately
        "build-tools:debian") echo "build-essential" ;;
        "build-tools:redhat") echo "gcc make" ;;
        "build-tools:arch") echo "base-devel" ;;
        *) echo "" ;;
    esac
}

# Check pkg-config
check_pkg_config() {
    log_info "Checking for pkg-config..."
    if command_exists pkg-config; then
        PKG_CONFIG_OK=true
        local version=$(pkg-config --version)
        log_success "pkg-config found (version $version)"
    else
        PKG_CONFIG_OK=false
        log_error "pkg-config not found"

        if [[ "$AUTO_INSTALL" == true ]]; then
            local packages=$(get_package_names "pkg-config")
            if [[ -n "$packages" ]] && install_package "$packages"; then
                if command_exists pkg-config; then
                    PKG_CONFIG_OK=true
                    local version=$(pkg-config --version)
                    log_success "pkg-config installed successfully (version $version)"
                    return
                fi
            fi
            log_error "Failed to install pkg-config automatically"
            echo "  Please install pkg-config manually and try again."
        fi

        echo "  pkg-config is required for dependency management."
        echo "  Install failed - please install manually or check system package manager."
        DEPS_OK=false
    fi
}

# Check for jansson library
check_jansson() {
    log_info "Checking for jansson (JSON library)..."
    if command_exists pkg-config && pkg-config --exists jansson; then
        JANSSON_OK=true
        local version=$(pkg-config --modversion jansson)
        local cflags=$(pkg-config --cflags jansson)
        local libs=$(pkg-config --libs jansson)
        log_success "jansson found (version $version)"
        if [[ "$VERBOSE" == true ]]; then
            echo "  CFLAGS: $cflags"
            echo "  LIBS: $libs"
        fi
    else
        JANSSON_OK=false
        log_error "jansson not found"

        if [[ "$AUTO_INSTALL" == true ]]; then
            local packages=$(get_package_names "jansson")
            if [[ -n "$packages" ]] && install_package "$packages"; then
                if pkg-config --exists jansson; then
                    JANSSON_OK=true
                    local version=$(pkg-config --modversion jansson)
                    log_success "jansson installed successfully (version $version)"
                    return
                fi
            fi
            log_error "Failed to install jansson automatically"
            echo "  Please install jansson manually and try again."
        fi

        echo "  jansson is required for JSON parsing."
        echo "  Install failed - please install manually or check system package manager."
        DEPS_OK=false
    fi
}

# Check for libcurl
check_curl() {
    log_info "Checking for libcurl (HTTP library)..."
    if command_exists pkg-config && pkg-config --exists libcurl; then
        CURL_OK=true
        local version=$(pkg-config --modversion libcurl)
        local cflags=$(pkg-config --cflags libcurl)
        local libs=$(pkg-config --libs libcurl)
        log_success "libcurl found (version $version)"
        if [[ "$VERBOSE" == true ]]; then
            echo "  CFLAGS: $cflags"
            echo "  LIBS: $libs"
        fi
    else
        CURL_OK=false
        log_error "libcurl not found"

        if [[ "$AUTO_INSTALL" == true ]]; then
            local packages=$(get_package_names "curl")
            if [[ -n "$packages" ]] && install_package "$packages"; then
                if pkg-config --exists libcurl; then
                    CURL_OK=true
                    local version=$(pkg-config --modversion libcurl)
                    log_success "libcurl installed successfully (version $version)"
                    return
                fi
            fi
            log_error "Failed to install libcurl automatically"
            echo "  Please install libcurl manually and try again."
        fi

        echo "  libcurl is required for HTTP requests."
        echo "  Install failed - please install manually or check system package manager."
        DEPS_OK=false
    fi
}

# Check C compiler
check_compiler() {
    log_info "Checking for C compiler ($CC)..."
    if command_exists "$CC"; then
        local version_output
        if version_output=$("$CC" --version 2>&1 | head -1); then
            log_success "C compiler found: $version_output"
        else
            log_success "C compiler found: $CC"
        fi
    else
        log_error "C compiler '$CC' not found"

        if [[ "$AUTO_INSTALL" == true ]]; then
            local os=$(detect_os)
            case $os in
                macos)
                    log_info "Installing Xcode command line tools..."
                    if xcode-select --install 2>/dev/null; then
                        log_info "Xcode tools installation started. Please complete the installation and run configure again."
                        exit 0
                    else
                        log_warning "Xcode tools may already be installed"
                    fi
                    ;;
                *)
                    local packages=$(get_package_names "build-tools")
                    if [[ -n "$packages" ]] && install_package "$packages"; then
                        if command_exists "$CC" || command_exists "gcc" || command_exists "clang"; then
                            # Update CC if default cc doesn't exist but gcc/clang does
                            if [[ "$CC" == "cc" ]] && ! command_exists "cc"; then
                                if command_exists "gcc"; then
                                    CC="gcc"
                                elif command_exists "clang"; then
                                    CC="clang"
                                fi
                            fi
                            log_success "C compiler installed successfully"
                            return
                        fi
                    fi
                    log_error "Failed to install C compiler automatically"
                    ;;
            esac
        fi

        echo "  A C compiler is required to build slq."
        echo "  Run: ./configure --auto-install"
        DEPS_OK=false
    fi
}

# Check for make
check_make() {
    log_info "Checking for make..."
    if command_exists make; then
        local version=$(make --version 2>&1 | head -1 || echo "make")
        log_success "make found: $version"
    else
        log_error "make not found"
        echo "  GNU make is required to build slq."
        echo "  Please install make and try again."
        DEPS_OK=false
    fi
}

# Check optional tools
check_optional_tools() {
    log_header "Optional Tools"

    # GitHub CLI for publishing
    if command_exists gh; then
        if gh auth status &> /dev/null; then
            log_success "GitHub CLI found and authenticated"
        else
            log_warning "GitHub CLI found but not authenticated"
            echo "  Run 'gh auth login' to enable publishing features"
        fi
    else
        log_warning "GitHub CLI not found"
        echo "  Install 'gh' to enable 'make publish' functionality"
        echo "  See: https://cli.github.com/"
    fi

    # clang-tidy for linting
    if command_exists clang-tidy; then
        log_success "clang-tidy found (enables 'make lint')"
    else
        log_warning "clang-tidy not found"
        echo "  Install clang-tidy to enable static analysis"
    fi

    # bear for compile_commands.json
    if command_exists bear; then
        log_success "bear found (enables 'make compile-commands')"
    else
        log_warning "bear not found"
        echo "  Install bear to generate compile_commands.json for editors"
    fi
}

# Generate config.mk file
generate_config() {
    log_info "Generating config.mk..."

    local cflags="-Wall -Wextra -std=c99"
    local libs=""

    # Add optimization or debug flags
    if [[ "$DEBUG" == true ]]; then
        cflags="$cflags -g -DDEBUG"
        log_info "Debug mode enabled"
    else
        cflags="$cflags -O2"
    fi

    # Add sanitizer flags
    if [[ "$ENABLE_SANITIZERS" == true ]]; then
        cflags="$cflags -fsanitize=address,undefined -fno-omit-frame-pointer"
        libs="$libs -fsanitize=address,undefined"
        log_info "Sanitizers enabled"
    fi

    # Add static linking
    if [[ "$ENABLE_STATIC" == true ]]; then
        libs="$libs -static"
        log_info "Static linking enabled"
    fi

    # Add pkg-config flags
    if [[ "$PKG_CONFIG_OK" == true ]]; then
        cflags="$cflags \$(shell pkg-config --cflags jansson libcurl)"
        libs="$libs \$(shell pkg-config --libs jansson libcurl)"
    fi

    cat > config.mk << EOF
# Generated by configure script - do not edit manually
# Run ./configure to regenerate this file

# Build configuration
CC = $CC
PREFIX = $PREFIX
DEBUG = $DEBUG
ENABLE_SANITIZERS = $ENABLE_SANITIZERS
ENABLE_STATIC = $ENABLE_STATIC

# Compiler flags
CFLAGS = $cflags
LIBS = $libs

# Dependencies status
JANSSON_OK = $JANSSON_OK
CURL_OK = $CURL_OK
PKG_CONFIG_OK = $PKG_CONFIG_OK
EOF

    log_success "Configuration saved to config.mk"
}

# Show build summary
show_summary() {
    log_header "Configuration Summary"
    echo "Compiler:        $CC"
    echo "Install prefix:  $PREFIX"
    echo "Debug mode:      $DEBUG"
    echo "Sanitizers:      $ENABLE_SANITIZERS"
    echo "Static linking:  $ENABLE_STATIC"
    echo ""
    echo "Dependencies:"
    echo "  pkg-config:    $([ "$PKG_CONFIG_OK" = true ] && echo "✓" || echo "✗")"
    echo "  jansson:       $([ "$JANSSON_OK" = true ] && echo "✓" || echo "✗")"
    echo "  libcurl:       $([ "$CURL_OK" = true ] && echo "✓" || echo "✗")"
    echo ""

    if [[ "$DEPS_OK" == true ]]; then
        log_success "All dependencies satisfied!"
        echo ""
        echo "You can now build slq with:"
        echo "  make"
        echo "  make install"
        echo ""
        echo "For development:"
        echo "  make test-all"
        echo "  make lint"
        echo ""
        echo "To publish releases (requires GitHub CLI):"
        echo "  make publish-dry"
        echo "  make release"
    else
        log_error "Missing dependencies detected"
        if [[ "$AUTO_INSTALL" == true ]]; then
            echo "Some dependencies could not be installed automatically."
            echo "Please install them manually and run configure again."
        else
            echo "Please install missing dependencies and run configure again."
        fi
        exit 1
    fi
}

# Main execution
main() {
    log_header "slq Configuration"
    echo "Checking build environment and dependencies..."

    parse_args "$@"

    log_header "Required Dependencies"
    check_pkg_config
    check_jansson
    check_curl
    check_compiler
    check_make

    check_optional_tools

    if [[ "$DEPS_OK" == true ]]; then
        generate_config
    fi

    show_summary
}

# Run main function with all arguments
main "$@"
