.POSIX:

CC = gcc
CFLAGS = -std=c17 \
  -pedantic -pedantic-errors -Werror -Wall -Wextra -Wshadow \
  -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition \
  -Wformat=2 -Wcast-qual -Wwrite-strings -Winit-self -Wnull-dereference \
  -Wdouble-promotion -Wconversion -Wsign-conversion -Wsign-compare \
  -Wtype-limits -Wunreachable-code -Wswitch-enum -Wswitch-default \
  -Wundef -Wendif-labels -Wpointer-arith -Wredundant-decls \
  -Wbad-function-cast -Wmissing-noreturn -Wnested-externs -Wlogical-op \
  -Wclobbered -Wfloat-equal -Wrestrict -Wsequence-point -Waddress \
  -Wvla -Wduplicated-cond -Wduplicated-branches -fno-common -ftrapv \
  -fstack-protector-strong

DEBUG_FLAGS = -g3 -O0 -fsanitize=undefined
RELEASE_FLAGS = -O2 -s -D NDEBUG

all: help

help:
	@echo "Please use: 'make init', 'make debug', 'make fast', 'make release', or 'make clean'"
	@echo "Supports parallel builds (e.g., 'make -j8 debug')"

init:
	@mkdir -p output source_code includes config
	@touch config/version source_code/main.c
	@echo "_00.000.00.0000" > config/version
	@echo "Project initialized."

clean:
	@rm -rf output/obj_debug output/obj_release config/*.mk
	@rm -f output/*
	@echo "Project Cleaned"

# ------------------------------
# Dynamic Build Graph Generators
debug:
	@mkdir -p config output/obj_debug
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null || echo "_00.000.00.0000"); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/debug.mk"; \
	echo ".POSIX:" > $$MK; \
	HEADERS=$$(find includes -type f -name '*.h' | tr '\n' ' '); \
	OBJS=""; \
	for SRC in $$(find source_code -type f -name '*.c'); do \
		OBJ="output/obj_debug/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC $$HEADERS" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$(CC) $(CFLAGS) $(DEBUG_FLAGS) -I includes -c $$SRC -o $$OBJ" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$(CC) $(CFLAGS) $(DEBUG_FLAGS) -o $$OUT $$OBJS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"

fast:
	@mkdir -p config output/obj_release
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null || echo "_00.000.00.0000"); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/fast.mk"; \
	echo ".POSIX:" > $$MK; \
	HEADERS=$$(find includes -type f -name '*.h' | tr '\n' ' '); \
	OBJS=""; \
	for SRC in $$(find source_code -type f -name '*.c'); do \
		OBJ="output/obj_release/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC $$HEADERS" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -I includes -c $$SRC -o $$OBJ" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -o $$OUT $$OBJS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"

release:
	@mkdir -p config output/obj_release
	@DATE_STR=$$(date +_%y.%j.%H.%M%S); \
	echo "$$DATE_STR" > config/version; \
	echo "Project version updated to: $$DATE_STR"
	@PROJ_NAME=$$(basename "$$(pwd)"); \
	VERS=$$(cat config/version 2>/dev/null); \
	OUT="output/$${PROJ_NAME}$${VERS}"; \
	MK="config/release.mk"; \
	echo ".POSIX:" > $$MK; \
	HEADERS=$$(find includes -type f -name '*.h' | tr '\n' ' '); \
	OBJS=""; \
	for SRC in $$(find source_code -type f -name '*.c'); do \
		OBJ="output/obj_release/$${SRC}.o"; \
		OBJS="$$OBJS $$OBJ"; \
		echo "$$OBJ: $$SRC $$HEADERS" >> $$MK; \
		echo "	@mkdir -p $$(dirname $$OBJ)" >> $$MK; \
		echo "	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -I includes -c $$SRC -o $$OBJ" >> $$MK; \
	done; \
	echo "$$OUT: $$OBJS" >> $$MK; \
	echo "	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -o $$OUT $$OBJS" >> $$MK; \
	$(MAKE) -f $$MK "$$OUT"
