# Note: Any variables prefixed with `.` are used for text
# replacement in the Makevars.in and Makevars.win.in

# check the packages MSRV first
source("tools/msrv.R")

# check DEBUG and NOT_CRAN environment variables
env_debug <- Sys.getenv("DEBUG")
env_not_cran <- Sys.getenv("NOT_CRAN")

# check if the vendored zip file exists
vendor_exists <- file.exists("src/rust/vendor.tar.xz")

is_not_cran <- env_not_cran != ""
is_debug <- env_debug != ""

if (is_debug) {
  # if we have DEBUG then we set not cran to true
  # CRAN is always release build
  is_not_cran <- TRUE
  message("Creating DEBUG build.")
}

if (!is_not_cran) {
  message("Building for CRAN.")
}

# we set cran flags only if NOT_CRAN is empty and if
# the vendored crates are present.
.cran_flags <- ifelse(
  !is_not_cran && vendor_exists,
  "-j 2 --offline",
  ""
)

# when DEBUG env var is present we use `--debug` build
.profile <- ifelse(is_debug, "", "--release")
.clean_targets <- ifelse(is_debug, "", "$(TARGET_DIR)")

# We specify this target when building for webR
webr_target <- "wasm32-unknown-emscripten"

# here we check if the platform we are building for is webr
is_wasm <- identical(R.version$platform, webr_target)

# print to terminal to inform we are building for webr
if (is_wasm) {
  message("Building for WebR")
}

# we check if we are making a debug build or not
# if so, the LIBDIR environment variable becomes:
# LIBDIR = $(TARGET_DIR)/{wasm32-unknown-emscripten}/debug
# this will be used to fill out the LIBDIR env var for Makevars.in
target_libpath <- if (is_wasm) "wasm32-unknown-emscripten" else NULL
cfg <- if (is_debug) "debug" else "release"

# used to replace @LIBDIR@
.libdir <- paste(c(target_libpath, cfg), collapse = "/")

# use this to replace @TARGET@
# we specify the target _only_ on webR
# there may be use cases later where this can be adapted or expanded
.target <- ifelse(is_wasm, paste0("--target=", webr_target), "")

# add panic exports only for WASM builds
.panic_exports <- ifelse(
  is_wasm,
  "CARGO_PROFILE_DEV_PANIC=\"abort\" CARGO_PROFILE_RELEASE_PANIC=\"abort\" ",
  ""
)

# On macOS, forward a deployment target into the cargo build so cc-rs
# compiles C/C++ deps (notably libduckdb-sys) with -mmacosx-version-min
# no newer than R's link step. Without this, cc defaults to the host SDK's
# max version and R CMD check flags a "newer macOS version than being
# linked" warning. Resolution order: explicit env var, then R's CFLAGS,
# then a conservative floor of 11.0 (the Apple Silicon minimum) which is
# older than any modern macOS so the linker won't complain.
.macos_target <- ""
if (Sys.info()[["sysname"]] == "Darwin") {
  dt <- Sys.getenv("MACOSX_DEPLOYMENT_TARGET", unset = "")
  if (!nzchar(dt)) {
    cflags <- tryCatch(
      suppressWarnings(system2(
        file.path(R.home("bin"), "R"),
        c("CMD", "config", "CFLAGS"),
        stdout = TRUE,
        stderr = FALSE
      )),
      error = function(e) character()
    )
    m <- regmatches(
      cflags,
      regexpr("-mmacosx-version-min=([0-9.]+)", cflags)
    )
    if (length(m) > 0) {
      dt <- sub("-mmacosx-version-min=", "", m[[1]])
    }
  }
  if (!nzchar(dt)) {
    dt <- "11.0"
  }
  .macos_target <- paste0("MACOSX_DEPLOYMENT_TARGET=", dt, " ")
}

# Resolve ODBC driver manager flags (unixODBC or iODBC). The ggsql Rust
# crate dynamically loads the ODBC driver manager via `libloading` (dlopen)
# at runtime, so `-lodbc` is not required at link time -- cargo's
# `native-static-libs` print confirms this. We therefore default to empty
# and only add flags when pkg-config can actually locate an ODBC .pc file.
#
# When pkg-config finds odbc, we keep only `-L/-l` tokens from its output:
# some iODBC .pc files (notably the one shipped on the CRAN sonoma-arm64
# builder) embed a stray `libltdl/libltdlc.la` libtool archive path in
# their Libs line that the linker can't resolve. Restricting to `-L`/`-l`
# strips those out.
#
# Hard-coding a `-lodbc` fallback would break platforms where libodbc is
# not on the linker's default search path (e.g. CRAN's R-devel M1 builder),
# and is unnecessary because the Rust side resolves ODBC symbols at
# runtime, not link time.
.odbc_libs <- tryCatch(
  {
    out <- suppressWarnings(system2(
      "pkg-config",
      c("--libs", "odbc"),
      stdout = TRUE,
      stderr = FALSE
    ))
    if (!is.null(attr(out, "status")) || length(out) == 0) {
      ""
    } else {
      tokens <- unlist(strsplit(paste(out, collapse = " "), "\\s+"))
      tokens <- tokens[nzchar(tokens)]
      tokens <- tokens[grepl("^-[Ll]", tokens)]
      paste(tokens, collapse = " ")
    }
  },
  error = function(e) ""
)

# read in the Makevars.in file checking
is_windows <- .Platform[["OS.type"]] == "windows"

# if windows we replace in the Makevars.win.in
mv_fp <- ifelse(
  is_windows,
  "src/Makevars.win.in",
  "src/Makevars.in"
)

# set the output file
mv_ofp <- ifelse(
  is_windows,
  "src/Makevars.win",
  "src/Makevars"
)

# delete the existing Makevars{.win/.wasm}
if (file.exists(mv_ofp)) {
  message("Cleaning previous `", mv_ofp, "`.")
  invisible(file.remove(mv_ofp))
}

# read as a single string
mv_txt <- readLines(mv_fp)

# replace placeholder values
new_txt <- gsub("@CRAN_FLAGS@", .cran_flags, mv_txt) |>
  gsub("@PROFILE@", .profile, x = _) |>
  gsub("@CLEAN_TARGET@", .clean_targets, x = _) |>
  gsub("@LIBDIR@", .libdir, x = _) |>
  gsub("@TARGET@", .target, x = _) |>
  gsub("@PANIC_EXPORTS@", .panic_exports, x = _) |>
  gsub("@MACOSX_TARGET@", .macos_target, x = _) |>
  gsub("@ODBC_LIBS@", .odbc_libs, x = _)

message("Writing `", mv_ofp, "`.")
con <- file(mv_ofp, open = "wb")
writeLines(new_txt, con, sep = "\n")
close(con)

message("`tools/config.R` has finished.")
