#cmake_minimum_required(VERSION 3.14)
#cmake_minimum_required(VERSION 3.18) # for BLAS::BLAS
cmake_minimum_required(VERSION 3.19) # for HDF5::HDF5
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # to prevent warnings about "Compatibility with CMake < 3.5 has been removed from CMake."

project(rl_tools_core)

set(CMAKE_CXX_STANDARD 17)

option(RL_TOOLS_ENABLE_TARGETS "Enable building the main targets" ON)
option(RL_TOOLS_ENABLE_TESTS "Enable building the tests" OFF)
option(RL_TOOLS_OFFLINE_BUILD "Use the dependencies in .dependencies without checking for updates (useful after nuking the build directory when offline)" OFF)
option(RL_TOOLS_WARNINGS_AS_ERRORS "Treat warnings as errors" ON)

option(RL_TOOLS_RL_ENVIRONMENTS_ENABLE_MUJOCO "Enable MuJoCo" OFF)
option(RL_TOOLS_RENDERING_ENABLE_RAYTRACING "Enable raytracing" OFF)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
endif()

add_library(rl_tools_core INTERFACE)
add_library(RLtools::Core ALIAS rl_tools_core)
target_compile_features(rl_tools_core INTERFACE cxx_std_17)
target_include_directories(rl_tools_core INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)

add_library(rl_tools_full INTERFACE)
add_library(RLtools::RLtools ALIAS rl_tools_full)
target_link_libraries(rl_tools_full INTERFACE rl_tools_core)

# Compiler optimizations
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
        target_compile_options(rl_tools_full INTERFACE -O3 -ffast-math -march=native)
    endif()
    if(RL_TOOLS_WARNINGS_AS_ERRORS)
        # Safe (just unused warnings)
        target_compile_options(rl_tools_full INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-Werror -Wall -Wextra>) # the $<$<COMPILE_LANGUAGE:CXX>: is required for NVCC to not complain about -Wall
        target_compile_options(rl_tools_full INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-Wno-unused-parameter -Wno-unused-local-typedefs -Wno-unused-variable -Wno-unused-but-set-variable>)
        if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
            target_compile_options(rl_tools_full INTERFACE -Wno-unused-lambda-capture)
        endif()

        # todo (put exclusions here)
        if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
            include(CheckCXXCompilerFlag)
            check_cxx_compiler_flag("-Wnan-infinity-disabled" HAS_NAN_INF_WARN)
            if (HAS_NAN_INF_WARN)
                target_compile_options(rl_tools_full INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-Wno-error=nan-infinity-disabled>) # clang does not like some NaN handling in nlohmann_json when -ffast-math is on
            endif()
        endif()
    endif()
elseif(MSVC)
    if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
        target_compile_options(rl_tools_full INTERFACE /O2 /fp:fast)
    endif()
    target_compile_options(rl_tools_full INTERFACE /bigobj)
    target_compile_definitions(rl_tools_full INTERFACE _CRT_SECURE_NO_WARNINGS)
    if(RL_TOOLS_WARNINGS_AS_ERRORS)
        target_compile_options(rl_tools_full INTERFACE /W3 /WX)
        target_compile_options(rl_tools_full INTERFACE
            /wd4100  # unreferenced formal parameter
            /wd4101  # unreferenced local variable
            /wd4146  # unary minus on unsigned type
            /wd4189  # local variable initialized but not referenced
            /wd4244  # conversion, possible loss of data
            /wd4267  # conversion from size_t, possible loss of data
            /wd4459  # declaration hides global
            /wd4996  # deprecated functions (getenv etc.)
            /wd4068  # unknown pragma (e.g. #pragma GCC)
            /wd4804  # unsafe use of type 'bool' in operation
        )
    endif()
endif()


# Configure FetchContent
get_filename_component(CMAKE_BINARY_DIR_BASENAME ${CMAKE_BINARY_DIR} NAME)
if(NOT DEFINED FETCHCONTENT_BASE_DIR)
    set(_test_file "${CMAKE_CURRENT_SOURCE_DIR}/.cmake_write_test")
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E touch "${_test_file}"
        RESULT_VARIABLE _write_test_result
        ERROR_QUIET
        OUTPUT_QUIET
    )
    if(_write_test_result EQUAL 0)
        file(REMOVE "${_test_file}")
        set(_fetchcontent_base_dir_root "${CMAKE_CURRENT_SOURCE_DIR}")
    else()
        set(_fetchcontent_base_dir_root "${CMAKE_CURRENT_BINARY_DIR}")
    endif()
    set(FETCHCONTENT_BASE_DIR "${_fetchcontent_base_dir_root}/.dependencies/${CMAKE_BINARY_DIR_BASENAME}" CACHE PATH "Base dir for FetchContent downloads" FORCE)
else()
    set(FETCHCONTENT_BASE_DIR "${FETCHCONTENT_BASE_DIR}/${CMAKE_BINARY_DIR_BASENAME}" CACHE PATH "Base dir for FetchContent downloads")
endif()
if(RL_TOOLS_OFFLINE_BUILD)
    set(FETCHCONTENT_FULLY_DISCONNECTED ON)
endif()
include(FetchContent)

# Suppress STATUS messages from FetchContent subprojects (arch details, feature
# summaries, proto generation lists, …) while still forwarding WARNING/ERROR.
# Requires CMake >= 3.25; silently ignored on older versions.
macro(rl_tools_fetchcontent_makeavailable_quiet)
    set(_rl_tools_prev_log_level ${CMAKE_MESSAGE_LOG_LEVEL})
    set(_rl_tools_prev_deprecation_flag ${CMAKE_WARN_DEPRECATED})
    set(CMAKE_MESSAGE_LOG_LEVEL ERROR)
    set(CMAKE_WARN_DEPRECATED FALSE)
    FetchContent_MakeAvailable(${ARGN})
    set(CMAKE_MESSAGE_LOG_LEVEL ${_rl_tools_prev_log_level})
    set(CMAKE_WARN_DEPRECATED ${_rl_tools_prev_deprecation_flag})
endmacro()

include(cmake/autodetect/all.cmake)

if(RL_TOOLS_RL_ENVIRONMENTS_ENABLE_MUJOCO)
    include(cmake/optional/mujoco.cmake)
endif()

set(RL_TOOLS_RENDERING_RAYTRACING_BACKEND "AUTO" CACHE STRING "Raytracing backend (AUTO|OPTIX|METAL|VULKAN|GENERIC)")
if(RL_TOOLS_RENDERING_ENABLE_RAYTRACING)
    set(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED ${RL_TOOLS_RENDERING_RAYTRACING_BACKEND})
    if(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED STREQUAL "AUTO")
        if(APPLE)
            set(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED "METAL")
        else()
            set(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED "OPTIX")
        endif()
    endif()
    message(STATUS "RLtools raytracing backend: ${RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED}")
    if(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED STREQUAL "METAL")
        include(cmake/optional/metal.cmake)
    elseif(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED STREQUAL "OPTIX")
        include(cmake/optional/optix.cmake)
    elseif(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED STREQUAL "VULKAN")
        include(cmake/optional/vulkan.cmake)
    elseif(RL_TOOLS_RENDERING_RAYTRACING_BACKEND_RESOLVED STREQUAL "GENERIC")
        include(cmake/optional/raytracing_generic.cmake)
    else()
        message(FATAL_ERROR "Invalid RL_TOOLS_RENDERING_RAYTRACING_BACKEND: ${RL_TOOLS_RENDERING_RAYTRACING_BACKEND}")
    endif()
endif()

if(RL_TOOLS_ENABLE_TARGETS)
    add_subdirectory(src)
endif()

if (RL_TOOLS_ENABLE_TESTS)
    include(cmake/optional/googletest.cmake)
    if(RL_TOOLS_ENABLE_GTEST)
        if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/data)
            set(RL_TOOLS_TEST_DATA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests/data" CACHE PATH "Path to test data")
            target_compile_definitions(rl_tools_full INTERFACE RL_TOOLS_TEST_DATA_PATH=${RL_TOOLS_TEST_DATA_PATH})
        endif()
        include(CTest)
        add_subdirectory(tests)
    endif()
endif()
