cmake_minimum_required(VERSION 3.12)
project(enter_the_fog C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 1. BUILD PROFILES
set(BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/binary")
set(CMAKE_C_FLAGS_RELEASE "-O2 -s")
set(CMAKE_C_FLAGS_DEBUG "-g -O0")

# --- SANITIZER LOGIC ---
# Enables ThreadSanitizer only when CMAKE_BUILD_TYPE is Debug
set(SANITIZER_FLAGS "")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    message(STATUS "Debug build detected: Enabling ThreadSanitizer")
    set(SANITIZER_FLAGS "-fsanitize=address")
endif()

# 2. DEPENDENCIES
find_package(PkgConfig REQUIRED)
pkg_check_modules(RAYLIB REQUIRED raylib)

# 3. SOURCE DISCOVERY
file(GLOB_RECURSE ALL_C_FILES "${CMAKE_CURRENT_SOURCE_DIR}/source_code/*.c")
file(GLOB_RECURSE ALL_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/source_code/*.h")

set(PROJECT_INCLUDE_DIRS "")
set(EXTERN_INCLUDE_DIRS "")

foreach(_header ${ALL_HEADERS})
    get_filename_component(_dir ${_header} DIRECTORY)
    if(_dir MATCHES "/external_code/")
        list(APPEND EXTERN_INCLUDE_DIRS ${_dir})
    else()
        list(APPEND PROJECT_INCLUDE_DIRS ${_dir})
    endif()
endforeach()

list(REMOVE_DUPLICATES PROJECT_INCLUDE_DIRS)
list(REMOVE_DUPLICATES EXTERN_INCLUDE_DIRS)

set(TEST_SOURCES "")
set(EXTERN_SOURCES "")
set(CORE_SOURCES "")

foreach(_file ${ALL_C_FILES})
    if(_file MATCHES ".*/test_[^/]+\\.c$" OR _file MATCHES ".*/tests/.*")
        list(APPEND TEST_SOURCES ${_file})
    elseif(_file MATCHES ".*/external_code/.*")
        list(APPEND EXTERN_SOURCES ${_file})
    elseif(NOT _file MATCHES ".*/main\\.c$" AND NOT _file MATCHES ".*/test_main\\.c$")
        list(APPEND CORE_SOURCES ${_file})
    endif()
endforeach()

# 4. TARGETS

# --- EXTERN LIB (Third party code) ---
add_library(enter_the_fog_extern STATIC ${EXTERN_SOURCES})
target_include_directories(enter_the_fog_extern SYSTEM PUBLIC ${EXTERN_INCLUDE_DIRS})

# --- CORE LIB (Your code) ---
add_library(enter_the_fog_core STATIC ${CORE_SOURCES})
target_include_directories(enter_the_fog_core PUBLIC ${PROJECT_INCLUDE_DIRS})
target_link_libraries(enter_the_fog_core PRIVATE enter_the_fog_extern)

# Apply Sanitizers to Core
target_compile_options(enter_the_fog_core PRIVATE 
    -Wall -Wextra -Wpedantic -Werror -Wconversion -Wsign-conversion -Wunused-variable -Wunused-function -Wmissing-declarations -Wshadow -Wno-implicit-fallthrough -Wredundant-decls -Wfloat-equal -Winline -Wnull-dereference -Waddress -Wno-long-long -Wimplicit-function-declaration
    ${SANITIZER_FLAGS})
target_link_options(enter_the_fog_core INTERFACE ${SANITIZER_FLAGS})

# --- EXECUTABLES ---

# Main Game
add_executable(enter_the_fog "${CMAKE_CURRENT_SOURCE_DIR}/source_code/main.c")
target_link_libraries(enter_the_fog enter_the_fog_core enter_the_fog_extern ${RAYLIB_LIBRARIES} m)
set_target_properties(enter_the_fog PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")
target_compile_options(enter_the_fog PRIVATE ${SANITIZER_FLAGS})
target_link_options(enter_the_fog PRIVATE ${SANITIZER_FLAGS})

# Test Suite
add_executable(test_suite "${CMAKE_CURRENT_SOURCE_DIR}/source_code/test_main.c" ${TEST_SOURCES})
target_link_libraries(test_suite enter_the_fog_core enter_the_fog_extern ${RAYLIB_LIBRARIES} m)
set_target_properties(test_suite PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")
target_compile_options(test_suite PRIVATE ${SANITIZER_FLAGS})
target_link_options(test_suite PRIVATE ${SANITIZER_FLAGS})

# 5. WORKFLOW COMMANDS (LSP Fix Included)
set(ROOT_JSON "${CMAKE_CURRENT_SOURCE_DIR}/compile_commands.json")

add_custom_target(test
    COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/../test"
    COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -B "${CMAKE_BINARY_DIR}/../test" -S "${CMAKE_SOURCE_DIR}"
    COMMAND ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}/../test" --target test_suite
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/../test/compile_commands.json" "${ROOT_JSON}"
    COMMAND "${BIN_DIR}/test_suite"
    COMMENT "Building and running tests with ThreadSanitizer...")

add_custom_target(debug
    COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/../debug"
    COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -B "${CMAKE_BINARY_DIR}/../debug" -S "${CMAKE_SOURCE_DIR}"
    COMMAND ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}/../debug" --target enter_the_fog
    # This specifically copies the JSON from the debug build folder to the root
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/../debug/compile_commands.json" "${ROOT_JSON}"
    COMMENT "Building debug binary and updating LSP commands...")

target_compile_options(enter_the_fog PRIVATE
    -Wall -Wextra -Wpedantic -Werror -Wconversion -Wsign-conversion -Wunused-variable -Wunused-function -Wmissing-declarations -Wshadow -Wno-implicit-fallthrough -Wredundant-decls -Wfloat-equal -Winline -Wnull-dereference -Waddress -Wno-long-long -Wimplicit-function-declaration
          ${SANITIZER_FLAGS})

target_compile_options(test_suite PRIVATE
    -Wall -Wextra -Wpedantic -Werror -Wconversion -Wsign-conversion -Wunused-variable -Wunused-function -Wmissing-declarations -Wshadow -Wno-implicit-fallthrough -Wredundant-decls -Wfloat-equal -Winline -Wnull-dereference -Waddress -Wno-long-long -Wimplicit-function-declaration
    ${SANITIZER_FLAGS})

# 6. INITIAL LSP SUPPORT
# Catch-all for when you run cmake manually from a build folder
if(EXISTS "${CMAKE_BINARY_DIR}/compile_commands.json")
    execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different 
        "${CMAKE_BINARY_DIR}/compile_commands.json" "${ROOT_JSON}")
endif()
