set(TARGET_BASE_NAME "${PRODUCT_NAME}")

set(TARGET_APP_NAME "${TARGET_BASE_NAME}")
set(TARGET_LIB_NAME "${TARGET_BASE_NAME}_lib")
set(TARGET_UI_NAME "${TARGET_BASE_NAME}_ui")
set(TARGET_TEST_NAME "${TARGET_BASE_NAME}_test")
set(TARGET_BALANCING_NAME "${TARGET_BASE_NAME}_balancing")

set(TARGET_LIB_INCLUDE_DIRS
    "${CMAKE_CURRENT_SOURCE_DIR}/lib"
    "${CMAKE_CURRENT_SOURCE_DIR}/external"
)
set(TARGET_UI_INCLUDE_DIRS
    "${CMAKE_CURRENT_SOURCE_DIR}/ui"
    # The balancing target compiles a few ui files into itself rather than linking the
    # ui library, and the ship stats panel is built from the selection card's parts.
    "${CMAKE_CURRENT_SOURCE_DIR}/ui/selection"
)
set(TARGET_TEST_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/test")
set(TARGET_BALANCING_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/balancing")

set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")


# ============================================================
# lib — simulation + config
# Depends on Qt Core, toml++, tinyexpr only (no QtWidgets).
# ============================================================

set(HDRS)
set(SRCS)
set(LIB_INCLUDE_PATH)

add_subdirectory(external)
add_subdirectory(lib)

set_source_files_properties(${EXTERNAL_FILES} PROPERTIES COMPILE_FLAGS "-w")

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

set(RELATIVE_HDRS)
foreach (_file ${HDRS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_HDRS "${_relPath}")
endforeach()

set(RELATIVE_SRCS)
foreach (_file ${SRCS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_SRCS "${_relPath}")
endforeach()

add_files(LIB_FILES ${RELATIVE_HDRS} ${RELATIVE_SRCS})

add_library(${TARGET_LIB_NAME} ${LIB_FILES} ${EXTERNAL_FILES})
create_source_groups(${LIB_FILES})
create_source_groups(${EXTERNAL_FILES})

set_property(TARGET ${TARGET_LIB_NAME} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${TARGET_LIB_NAME} PROPERTY INCLUDE_DIRECTORIES
    "${TARGET_LIB_INCLUDE_DIRS}"
    "${LIB_INCLUDE_PATH}"
)
target_link_libraries(${TARGET_LIB_NAME} Qt5::Core Qt5::Gui)
target_compile_definitions(${TARGET_LIB_NAME} PRIVATE TOML_FLOAT_CHARCONV=0)

set(CMAKE_AUTOMOC OFF)

unset(LIB_FILES)
unset(RELATIVE_HDRS)
unset(RELATIVE_SRCS)
unset(HDRS)
unset(SRCS)
# LIB_INCLUDE_PATH (populated by lib/ and external/ subdirectories) is kept
# in scope so the test target below can also reach those headers.


# ============================================================
# ui — QtWidgets + QOpenGLWidget
# Depends on lib.
# ============================================================

set(HDRS)
set(SRCS)
set(UI_INCLUDE_PATH)

add_subdirectory(ui)

set(CMAKE_AUTOMOC ON)

set(RELATIVE_HDRS)
foreach (_file ${HDRS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_HDRS "${_relPath}")
endforeach()

set(RELATIVE_SRCS)
foreach (_file ${SRCS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_SRCS "${_relPath}")
endforeach()

add_files(UI_FILES ${RELATIVE_HDRS} ${RELATIVE_SRCS})

add_library(${TARGET_UI_NAME} STATIC ${UI_FILES})
create_source_groups(${UI_FILES})

set_target_properties(${TARGET_UI_NAME} PROPERTIES
    AUTOMOC ON
    CXX_STANDARD 17
)
target_include_directories(${TARGET_UI_NAME} PUBLIC
    "${TARGET_UI_INCLUDE_DIRS}"
    "${UI_INCLUDE_PATH}"
    "${TARGET_LIB_INCLUDE_DIRS}"
    "${LIB_INCLUDE_PATH}"
)

target_link_libraries(${TARGET_UI_NAME}
    ${TARGET_LIB_NAME}
    Qt5::Widgets
    ${OPENGL_LIBRARIES}
    Qt5::Network
    Qt5::Multimedia
    Qt5::Charts
    Qt5::Svg
)
target_compile_definitions(${TARGET_UI_NAME} PRIVATE TOML_FLOAT_CHARCONV=0)

set(CMAKE_AUTOMOC OFF)

unset(UI_FILES)
unset(RELATIVE_HDRS)
unset(RELATIVE_SRCS)
unset(HDRS)
unset(SRCS)


# ============================================================
# app — thin main(); depends on ui
# ============================================================

set(OUTPUT_ROOT_PATH "${CMAKE_BINARY_DIR}/${TARGET_BASE_NAME}")

if (WIN32)
    COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Debug/app/" True)
    COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Release/app/" False)

    string(REGEX REPLACE "/" "\\\\" BACKSLASHED_CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
    string(REGEX REPLACE "/" "\\\\" BACKSLASHED_OUTPUT_ROOT_PATH ${OUTPUT_ROOT_PATH})
    execute_process(
        COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\app\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\app\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\app\\data" & exit
        COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\app\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\app\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\app\\data" & exit
    )
endif ()

foreach (OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
    string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${OUTPUT_ROOT_PATH}/${OUTPUTCONFIG}/app/")
endforeach ()

set(HDRS)
set(SRCS)

add_subdirectory(app)

set(RELATIVE_HDRS)
foreach (_file ${HDRS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_HDRS "${_relPath}")
endforeach()

set(RELATIVE_SRCS)
foreach (_file ${SRCS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_SRCS "${_relPath}")
endforeach()

add_files(APP_FILES ${RELATIVE_HDRS} ${RELATIVE_SRCS})

add_executable(${TARGET_APP_NAME} ${APP_FILES})
create_source_groups(${APP_FILES})

set_property(TARGET ${TARGET_APP_NAME} PROPERTY CXX_STANDARD 17)
set_target_properties(${TARGET_APP_NAME} PROPERTIES
    VS_DEBUGGER_WORKING_DIRECTORY "${OUTPUT_ROOT_PATH}/$(Configuration)/app/"
)
target_compile_definitions(${TARGET_APP_NAME} PRIVATE
    CONFIG_DIR="${CMAKE_SOURCE_DIR}/bin/app/data/config"
)
target_link_libraries(${TARGET_APP_NAME} ${TARGET_UI_NAME})

# Embed the Windows version resource so the version shows on the executable's
# Details tab (right-click -> Properties). Values come from cmake/version.cmake
# (version numbers) and the product identity variables in the top-level
# CMakeLists.txt. MSVC compiles the .rc automatically once it is a target source.
if (WIN32)
    configure_file(
        "${CMAKE_SOURCE_DIR}/cmake/version.rc.in"
        "${CMAKE_CURRENT_BINARY_DIR}/version.rc"
        @ONLY
    )
    target_sources(${TARGET_APP_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/version.rc")
endif ()

unset(APP_FILES)
unset(RELATIVE_HDRS)
unset(RELATIVE_SRCS)
unset(HDRS)
unset(SRCS)


# ============================================================
# balancing — ship balancing tool; depends on lib + QtWidgets
# ============================================================

if (WIN32)
    COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Debug/balancing/" True)
    COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Release/balancing/" False)

    execute_process(
        COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\balancing\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\balancing\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\balancing\\data" & exit
        COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\balancing\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\balancing\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\balancing\\data" & exit
    )
endif ()

set(HDRS)
set(SRCS)

add_subdirectory(balancing)

set(RELATIVE_HDRS)
foreach (_file ${HDRS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_HDRS "${_relPath}")
endforeach()

set(RELATIVE_SRCS)
foreach (_file ${SRCS})
    file(RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
    list(APPEND RELATIVE_SRCS "${_relPath}")
endforeach()

add_files(BALANCING_FILES ${RELATIVE_HDRS} ${RELATIVE_SRCS})

add_executable(${TARGET_BALANCING_NAME} ${BALANCING_FILES})
create_source_groups(${BALANCING_FILES})

foreach (OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
    string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
    set_target_properties(${TARGET_BALANCING_NAME} PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${OUTPUT_ROOT_PATH}/${OUTPUTCONFIG}/balancing/"
    )
endforeach ()

set_target_properties(${TARGET_BALANCING_NAME} PROPERTIES
    AUTOMOC ON
    CXX_STANDARD 17
    VS_DEBUGGER_WORKING_DIRECTORY "${OUTPUT_ROOT_PATH}/$(Configuration)/balancing/"
)
target_include_directories(${TARGET_BALANCING_NAME} PRIVATE
    "${TARGET_BALANCING_INCLUDE_DIRS}"
    "${TARGET_LIB_INCLUDE_DIRS}"
    "${TARGET_UI_INCLUDE_DIRS}"
    "${LIB_INCLUDE_PATH}"
)
target_compile_definitions(${TARGET_BALANCING_NAME} PRIVATE
    CONFIG_DIR="${CMAKE_SOURCE_DIR}/bin/app/data/config"
    BALANCING_CONFIG="${CMAKE_SOURCE_DIR}/bin/balancing/data/balancing.toml"
    TOML_FLOAT_CHARCONV=0
)
target_link_libraries(${TARGET_BALANCING_NAME} ${TARGET_LIB_NAME} Qt5::Widgets ${OPENGL_LIBRARIES})

unset(BALANCING_FILES)
unset(RELATIVE_HDRS)
unset(RELATIVE_SRCS)
unset(HDRS)
unset(SRCS)


# ============================================================
# tests — Catch2 tests; links against lib only (no QtWidgets)
# ============================================================

add_subdirectory(test)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

add_executable(${TARGET_TEST_NAME} ${TEST_FILES})
create_source_groups(${TEST_FILES})

set_property(TARGET ${TARGET_TEST_NAME} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${TARGET_TEST_NAME} PROPERTY INCLUDE_DIRECTORIES
    "${TARGET_TEST_INCLUDE_DIRS}"
    "${TARGET_LIB_INCLUDE_DIRS}"
    "${LIB_INCLUDE_PATH}"
)
target_compile_definitions(${TARGET_TEST_NAME} PRIVATE
    CONFIG_DIR="${CMAKE_SOURCE_DIR}/bin/test/data/config"
)
target_link_libraries(${TARGET_TEST_NAME} ${TARGET_LIB_NAME})


# ============================================================
# Export
# ============================================================

set(TARGET_LIB_NAME "${TARGET_LIB_NAME}" PARENT_SCOPE)
set(TARGET_UI_NAME "${TARGET_UI_NAME}" PARENT_SCOPE)
set(TARGET_APP_NAME "${TARGET_APP_NAME}" PARENT_SCOPE)
set(TARGET_BALANCING_NAME "${TARGET_BALANCING_NAME}" PARENT_SCOPE)
