# C library source
LIB_URL := https://github.com/bitcoin-core/secp256k1
COMMIT_HASH := v0.7.1

# --- Tools ---
CC ?= gcc
MAKE := $(MAKE)

# --- Directories ---
TARGET_DIR := ./priv
SRC_DIR := ./c_src
LIB_SRC_DIR := $(SRC_DIR)/secp256k1
LIB_BUILD_DIR := $(LIB_SRC_DIR)/.libs
LIB_STATIC_LIB := $(LIB_BUILD_DIR)/libsecp256k1.a

# --- Verbosity Control ---
# Default to quiet execution. Run `make V=1` for verbose output.
ifndef V
  QUIET_CMD = > /dev/null 2>&1
  QUIET_MAKE = --silent
  ECHO = @echo
else
  QUIET_CMD =
  QUIET_MAKE =
  ECHO = @\# # Echo command becomes a comment (no-op)
endif

# --- Build Flags ---
# Check for required Erlang include directory
ifeq ($(ERTS_INCLUDE_DIR),)
  $(error ERTS_INCLUDE_DIR is not set. Please set it, e.g., ERTS_INCLUDE_DIR=$$(erl -eval 'io:format("~s/erts-~s/include",[code:root_dir(), erlang:system_info(version)]).' -noshell -s init stop))
endif

CPPFLAGS += -I$(ERTS_INCLUDE_DIR)
CPPFLAGS += -I$(LIB_SRC_DIR)/include

CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CFLAGS += -fPIC # Required for shared objects

LDFLAGS ?=
LIBS ?=

# add macOS specific LDFLAGS
OS := $(shell uname -s)
ifeq ($(OS), Darwin)
  LDFLAGS += -undefined dynamic_lookup
endif

# --- secp256k1 Library Options ---
CONFIG_OPTS = --disable-benchmark --disable-tests --disable-fast-install --with-pic --enable-experimental --enable-module-musig

# --- Source Files & Targets ---
NIF_SOURCES = $(wildcard $(SRC_DIR)/*.c)
NIF_TARGETS = $(patsubst $(SRC_DIR)/%.c, $(TARGET_DIR)/%.so, $(NIF_SOURCES))

# Utility headers (used as dependencies to trigger rebuilds)
UTILS = $(SRC_DIR)/random.h $(SRC_DIR)/utils.h

# Stamp file to indicate secp256k1 source is fetched
FETCH_STAMP = $(LIB_SRC_DIR)/.fetched

# --- Default Target ---
.PHONY: all
all: $(NIF_TARGETS)

# --- NIF Compilation Rule ---
# $@ = target file ($(TARGET_DIR)/%.so)
# $< = first prerequisite ($(SRC_DIR)/%.c)
$(TARGET_DIR)/%.so: $(SRC_DIR)/%.c $(UTILS) $(LIB_STATIC_LIB)
	@mkdir -p $(@D)
	$(ECHO) "  CC       $@"
	@$(CC) $(CPPFLAGS) $(CFLAGS) -shared -o $@ $< $(LIB_STATIC_LIB) $(LDFLAGS) $(LIBS)

# --- secp256k1 Library Compilation Chain ---

# The static library depends on the Makefile existing *and* being configured
$(LIB_STATIC_LIB): $(LIB_SRC_DIR)/Makefile
	$(ECHO) "  MAKE     libsecp256k1"
	@$(MAKE) -C $(LIB_SRC_DIR) $(QUIET_MAKE) $(QUIET_CMD)

# The Makefile is created by configure
$(LIB_SRC_DIR)/Makefile: $(LIB_SRC_DIR)/configure
	$(ECHO) "  CONFIG   libsecp256k1"
	@cd $(LIB_SRC_DIR) && ./configure $(CONFIG_OPTS) $(QUIET_CMD)

# Configure script is generated by autogen.sh
$(LIB_SRC_DIR)/configure: $(LIB_SRC_DIR)/autogen.sh
	$(ECHO) "  AUTOGEN  libsecp256k1"
	@cd $(LIB_SRC_DIR) && ./autogen.sh $(QUIET_CMD)

# Autogen.sh comes from the fetched source, indicated by the stamp file
$(LIB_SRC_DIR)/autogen.sh: $(FETCH_STAMP)

# Fetch the source code only if the stamp file doesn't exist
$(FETCH_STAMP):
	$(ECHO) "  GIT      libsecp256k1 (commit: $(COMMIT_HASH))"
	@rm -rf $(LIB_SRC_DIR) # Remove potentially outdated dir before cloning
	@git clone --depth 1 --branch $(COMMIT_HASH) $(LIB_URL) $(LIB_SRC_DIR) $(QUIET_CMD)
	@touch $@ # Create the stamp file

# --- Cleaning Targets ---
.PHONY: clean distclean

# clean: Remove built NIFs and clean the library build artifacts
clean:
	$(ECHO) "  CLEAN    build artifacts"
	@rm -f $(TARGET_DIR)/*.so
	@if [ -f "$(LIB_SRC_DIR)/Makefile" ]; then \
		$(MAKE) -C $(LIB_SRC_DIR) clean $(QUIET_MAKE) $(QUIET_CMD); \
	fi

# distclean: Remove everything clean does, plus the fetched library source
distclean: clean
	$(ECHO) "  CLEAN    fetched sources"
	@rm -rf $(LIB_SRC_DIR)
