# Makefile for testing-utils project
# This replaces the Bazel build system with traditional make

# Configuration
PREFIX ?= /usr/local
DESTDIR ?=
PYTHON ?= python3
CARGO ?= cargo
CXX ?= g++
PKG_CONFIG ?= pkg-config

# Directories
BUILD_DIR = build
CPP_BUILD_DIR = $(BUILD_DIR)/cpp
RUST_BUILD_DIR = $(BUILD_DIR)/rust
PYTHON_BUILD_DIR = $(BUILD_DIR)/python

# C++ Configuration
CPP_SRCDIR = test_scenarios_cpp

# Check if score-baselibs is available
SCORE_AVAILABLE := $(shell pkg-config --exists score-json 2>/dev/null && echo yes || echo no)

ifeq ($(SCORE_AVAILABLE),yes)
CPP_SRC = $(CPP_SRCDIR)/src/cli.cpp \
          $(CPP_SRCDIR)/src/monotonic_clock.cpp \
          $(CPP_SRCDIR)/src/scenario.cpp \
          $(CPP_SRCDIR)/src/string_utils.cpp \
          $(CPP_SRCDIR)/src/test_context.cpp \
          $(CPP_SRCDIR)/src/tracing.cpp

CPP_HDR = $(CPP_SRCDIR)/include/cli.hpp \
          $(CPP_SRCDIR)/include/monotonic_clock.hpp \
          $(CPP_SRCDIR)/include/scenario.hpp \
          $(CPP_SRCDIR)/include/test_context.hpp \
          $(CPP_SRCDIR)/include/tracing.hpp
else
# Fallback: build without tracing if score-baselibs is not available
CPP_SRC = $(CPP_SRCDIR)/src/cli.cpp \
          $(CPP_SRCDIR)/src/monotonic_clock.cpp \
          $(CPP_SRCDIR)/src/scenario.cpp \
          $(CPP_SRCDIR)/src/string_utils.cpp \
          $(CPP_SRCDIR)/src/test_context.cpp

CPP_HDR = $(CPP_SRCDIR)/include/cli.hpp \
          $(CPP_SRCDIR)/include/monotonic_clock.hpp \
          $(CPP_SRCDIR)/include/scenario.hpp \
          $(CPP_SRCDIR)/include/test_context.hpp
endif

CPP_TEST_SRC = $(CPP_SRCDIR)/tests/test_cli.cpp \
               $(CPP_SRCDIR)/tests/test_scenario.cpp \
               $(CPP_SRCDIR)/tests/test_test_context.cpp

CPP_OBJ = $(CPP_SRC:$(CPP_SRCDIR)/%.cpp=$(CPP_BUILD_DIR)/%.o)
CPP_TEST_OBJ = $(CPP_TEST_SRC:$(CPP_SRCDIR)/%.cpp=$(CPP_BUILD_DIR)/%.o)

# C++ Flags
CXXFLAGS ?= -O2 -g -std=c++17 -Wall -Wextra
CPPFLAGS += -I$(CPP_SRCDIR)/include
LDFLAGS += $(shell $(PKG_CONFIG) --libs gtest gtest_main 2>/dev/null || echo -lgtest -lgtest_main -lpthread)
# Group score libraries with whole-archive to resolve circular dependencies (if available)
ifeq ($(SCORE_AVAILABLE),yes)
SCORE_LIBS = -Wl,--start-group -lscore_json -lscore_memory -lscore_futurecpp -lscore_safecpp -lscore_log -lscore_utils -lscore_os -lscore_result -lscore_containers -lscore_filesystem -lscore_analysis -lscore_bitmanipulation -lscore_concurrency -lscore_quality -Wl,--end-group
else
SCORE_LIBS =
endif

# Rust Configuration
RUST_SRCDIR = test_scenarios_rust
RUST_LIB = $(RUST_BUILD_DIR)/libtest_scenarios_rust.rlib

# Python Configuration
PYTHON_SRCDIR = testing_utils
PYTHON_SCRIPT = scripts/coverage_checker/coverage_checker.py

# Targets
.PHONY: all clean install uninstall test cpp rust python cpp-test rust-test python-test help

all: cpp rust python

help:
	@echo "Available targets:"
	@echo "  all          - Build all components (C++, Rust, Python)"
	@echo "  cpp          - Build C++ library"
	@echo "  rust         - Build Rust library"
	@echo "  python       - Build Python package"
	@echo "  test         - Run all tests"
	@echo "  cpp-test     - Build and run C++ tests"
	@echo "  rust-test    - Run Rust tests"
	@echo "  python-test  - Run Python tests"
	@echo "  install      - Install all components"
	@echo "  uninstall    - Uninstall all components"
	@echo "  clean        - Clean build artifacts"
	@echo "  help         - Show this help message"

# Create build directories
$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(CPP_BUILD_DIR): | $(BUILD_DIR)
	mkdir -p $(CPP_BUILD_DIR)/src $(CPP_BUILD_DIR)/tests

$(RUST_BUILD_DIR): | $(BUILD_DIR)
	mkdir -p $(RUST_BUILD_DIR)

$(PYTHON_BUILD_DIR): | $(BUILD_DIR)
	mkdir -p $(PYTHON_BUILD_DIR)

# C++ Library
cpp: $(CPP_BUILD_DIR)/libtest_scenarios_cpp.a

$(CPP_BUILD_DIR)/libtest_scenarios_cpp.a: $(CPP_OBJ) | $(CPP_BUILD_DIR)
	ar rcs $@ $(CPP_OBJ)

$(CPP_BUILD_DIR)/%.o: $(CPP_SRCDIR)/%.cpp | $(CPP_BUILD_DIR)
	@mkdir -p $(dir $@)
	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@

# C++ Tests
cpp-test: $(CPP_BUILD_DIR)/test_runner
	$(CPP_BUILD_DIR)/test_runner --gtest_catch_exceptions=0 || true

$(CPP_BUILD_DIR)/test_runner: $(CPP_TEST_OBJ) $(CPP_BUILD_DIR)/libtest_scenarios_cpp.a | $(CPP_BUILD_DIR)
	$(CXX) $(CXXFLAGS) $(CPP_TEST_OBJ) -L$(CPP_BUILD_DIR) -ltest_scenarios_cpp $(SCORE_LIBS) $(LDFLAGS) -o $@

# Rust Library
rust: $(RUST_LIB)

$(RUST_LIB): $(wildcard $(RUST_SRCDIR)/src/*.rs) $(RUST_SRCDIR)/Cargo.toml | $(RUST_BUILD_DIR)
	cd $(RUST_SRCDIR) && $(CARGO) build --release
	cp $(RUST_SRCDIR)/target/release/libtest_scenarios_rust.rlib $(RUST_LIB) 2>/dev/null || \
	cp $(RUST_SRCDIR)/target/release/deps/libtest_scenarios_rust-*.rlib $(RUST_LIB) 2>/dev/null || \
	echo "Warning: Rust library not found in expected location"

# Rust Tests
rust-test:
	cd $(RUST_SRCDIR) && $(CARGO) test

# Python Package
python: $(PYTHON_BUILD_DIR)/build_complete

$(PYTHON_BUILD_DIR)/build_complete: $(wildcard $(PYTHON_SRCDIR)/*.py) | $(PYTHON_BUILD_DIR)
	# For RPM builds, we don't need to build wheels - just mark as complete
	touch $@

# Python Tests
python-test:
	cd $(PYTHON_SRCDIR) && $(PYTHON) -m pytest . -v 2>/dev/null || echo "No Python tests found or pytest not available"

# Combined test target
test: cpp-test rust-test python-test

# Installation
install: all
	# Install C++ library and headers
	install -d $(DESTDIR)$(PREFIX)/lib64
	install -m 644 $(CPP_BUILD_DIR)/libtest_scenarios_cpp.a $(DESTDIR)$(PREFIX)/lib64/
	install -d $(DESTDIR)$(PREFIX)/include/test_scenarios_cpp
	install -m 644 $(CPP_HDR) $(DESTDIR)$(PREFIX)/include/test_scenarios_cpp/

	# Install Rust library (if built successfully)
	if [ -f $(RUST_LIB) ]; then \
		install -d $(DESTDIR)$(PREFIX)/lib64/rust; \
		install -m 644 $(RUST_LIB) $(DESTDIR)$(PREFIX)/lib64/rust/; \
	fi

	# Install Python package (unless PYTHON_INSTALL=no)
	if [ "$(PYTHON_INSTALL)" != "no" ] && [ -f $(PYTHON_BUILD_DIR)/build_complete ]; then \
		echo "Python installation is handled by RPM spec file"; \
	fi

# Uninstallation
uninstall:
	# Remove C++ library and headers
	rm -f $(DESTDIR)$(PREFIX)/lib/libtest_scenarios_cpp.a
	rm -rf $(DESTDIR)$(PREFIX)/include/test_scenarios_cpp

	# Remove Rust library
	rm -f $(DESTDIR)$(PREFIX)/lib/rust/libtest_scenarios_rust.rlib

	# Remove Python script
	rm -f $(DESTDIR)$(PREFIX)/bin/coverage_checker

	# Note: Python package uninstallation requires pip uninstall testing-utils

# Clean
clean:
	rm -rf $(BUILD_DIR)
	cd $(RUST_SRCDIR) && $(CARGO) clean 2>/dev/null || true
	find . -name "*.pyc" -delete
	find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true

# Dependencies for C++ object files
$(CPP_BUILD_DIR)/src/%.o: $(CPP_SRCDIR)/src/%.cpp $(CPP_HDR)
$(CPP_BUILD_DIR)/tests/%.o: $(CPP_SRCDIR)/tests/%.cpp $(CPP_HDR) $(CPP_SRCDIR)/tests/common.hpp