cmake_minimum_required(VERSION 3.24)
project(GundamSeedRecomp LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(MSVC)
  add_compile_options(/utf-8 /D_CRT_SECURE_NO_WARNINGS)
endif()
get_filename_component(WORK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../work" ABSOLUTE)
set(DEPS_DIR "${WORK_DIR}/deps" CACHE PATH "Checked out dependencies")
set(GENERATED_DIR "${WORK_DIR}/generated/us" CACHE PATH "Private generated US cartridge code")
set(SDL_SHARED ON CACHE BOOL "" FORCE)
set(SDL_STATIC OFF CACHE BOOL "" FORCE)
set(SDL_TESTS OFF CACHE BOOL "" FORCE)
add_subdirectory("${DEPS_DIR}/SDL3" "${CMAKE_BINARY_DIR}/sdl3" EXCLUDE_FROM_ALL)
set(GBARECOMP_HOST_WINDOW_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src/host_window_sdl3.cpp")
set(GBARECOMP_COMPILER_CACHE OFF CACHE STRING "" FORCE)
set(GBARECOMP_SELFHEAL_RECOMPILE_DEFAULT OFF CACHE BOOL "Enable runtime compilation of missing guest functions")
add_library(seed_codes STATIC src/invite_code.cpp)
target_include_directories(seed_codes PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(seed_codes PUBLIC SDL3::SDL3)
add_library(seed_profile STATIC src/player_profile.cpp)
target_include_directories(seed_profile PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
add_executable(seed_player_profile_tests tests/player_profile_tests.cpp)
target_link_libraries(seed_player_profile_tests PRIVATE seed_profile)
add_library(seed_links STATIC src/invite_window.cpp)
target_include_directories(seed_links PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(seed_links PUBLIC seed_codes user32 advapi32)
add_executable(seed_join_code_tests tests/join_code_tests.cpp)
target_link_libraries(seed_join_code_tests PRIVATE seed_codes)
add_executable(seed_invite_window_tests tests/invite_window_tests.cpp)
target_link_libraries(seed_invite_window_tests PRIVATE seed_links)
add_library(seed_controls STATIC src/input_bindings.cpp src/live_controls.cpp)
target_include_directories(seed_controls PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(seed_controls PUBLIC SDL3::SDL3)
add_executable(seed_controls_tests tests/input_bindings_tests.cpp)
target_link_libraries(seed_controls_tests PRIVATE seed_controls)
option(SEED_BUILD_GAME "Build the experimental game host and cartridge oracles" ON)
if(SEED_BUILD_GAME)
add_subdirectory("${DEPS_DIR}/gbarecomp" "${CMAKE_BINARY_DIR}/engine" EXCLUDE_FROM_ALL)
target_link_libraries(gbarecomp_runtime PUBLIC seed_controls)
file(GLOB SHARDS CONFIGURE_DEPENDS "${GENERATED_DIR}/recompiled_*.cpp")
if(NOT SHARDS)
  message(FATAL_ERROR "Generate the US cartridge first with build.ps1")
endif()

add_library(seed_cartridge STATIC ${SHARDS}
  "${GENERATED_DIR}/dispatch_table.cpp" "${GENERATED_DIR}/symbol_map.cpp")
target_include_directories(seed_cartridge PRIVATE "${DEPS_DIR}/gbarecomp/src/armv4t" "${GENERATED_DIR}")
add_executable(GundamSeedRecomp src/main.cpp src/local_vs_runtime.cpp src/main_menu_label.cpp src/jp_selection.cpp src/jp_selection_overlay.cpp)
target_link_gbarecomp_runtime_stack(GundamSeedRecomp seed_cartridge)
add_library(seed_input STATIC src/input_state.cpp src/local_vs.cpp)
target_include_directories(seed_input PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(GundamSeedRecomp PRIVATE seed_input SDL3::SDL3)
add_executable(seed_input_oracle tests/input_oracle.cpp)
add_executable(seed_local_vs_tests tests/local_vs_tests.cpp)
target_link_libraries(seed_local_vs_tests PRIVATE seed_input)
target_link_libraries(seed_input_oracle PRIVATE seed_input gbarecomp_armv4t)
add_executable(seed_jp_asset_oracle tests/jp_asset_oracle.cpp)
add_executable(seed_debug_stop_tests tests/debug_stop_tests.cpp)
target_link_gbarecomp_runtime_stack(seed_debug_stop_tests seed_cartridge)
add_executable(seed_in_game_remap_tests tests/in_game_remap_tests.cpp)
target_link_gbarecomp_runtime_stack(seed_in_game_remap_tests seed_cartridge)
add_executable(seed_online_lobby_tests tests/online_lobby_tests.cpp)
target_link_gbarecomp_runtime_stack(seed_online_lobby_tests seed_cartridge)
add_executable(seed_bios_fast_set_tests tests/bios_fast_set_tests.cpp)
target_link_gbarecomp_runtime_stack(seed_bios_fast_set_tests seed_cartridge)
target_link_libraries(seed_jp_asset_oracle PRIVATE gbarecomp_armv4t)
add_executable(seed_jp_asset_reference EXCLUDE_FROM_ALL tests/jp_asset_reference.cpp)
target_link_gbarecomp_runtime_stack(seed_jp_asset_reference seed_cartridge)
add_executable(seed_sdl3_host_tests tests/sdl3_host_tests.cpp src/jp_selection.cpp src/jp_selection_overlay.cpp)
target_link_gbarecomp_runtime_stack(seed_sdl3_host_tests seed_cartridge)
target_link_libraries(seed_sdl3_host_tests PRIVATE seed_input SDL3::SDL3)
file(GLOB JP_SHARDS CONFIGURE_DEPENDS "${WORK_DIR}/generated/jp/recompiled_*.cpp")
if(JP_SHARDS)
  file(GLOB GEKKO_SOURCES CONFIGURE_DEPENDS "${DEPS_DIR}/GekkoNet/GekkoLib/src/*.cpp")
  add_library(seed_gekkonet STATIC ${GEKKO_SOURCES})
  target_include_directories(seed_gekkonet PUBLIC "${DEPS_DIR}/GekkoNet/GekkoLib/include"
    PRIVATE "${DEPS_DIR}/GekkoNet/GekkoLib/include/private" "${DEPS_DIR}/GekkoNet/GekkoLib/thirdparty")
  target_compile_definitions(seed_gekkonet PUBLIC GEKKONET_STATIC GEKKONET_NO_ASIO)
  add_library(seed_transport STATIC src/udp_transport.cpp src/nat_traversal.cpp)
  target_include_directories(seed_transport PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
  target_link_libraries(seed_transport PUBLIC seed_gekkonet seed_codes SDL3::SDL3 ws2_32 iphlpapi bcrypt)
  add_executable(seed_nat_probe tests/nat_probe.cpp)
  target_link_libraries(seed_nat_probe PRIVATE seed_transport)
  add_library(seed_room STATIC src/online_room.cpp)
  target_include_directories(seed_room PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
  target_link_libraries(seed_room PUBLIC seed_transport seed_input seed_profile bcrypt)
  target_link_libraries(GundamSeedRecomp PRIVATE seed_room seed_links)
  target_sources(GundamSeedRecomp PRIVATE src/app.manifest)
  add_executable(seed_online_room_tests tests/online_room_tests.cpp)
  target_link_libraries(seed_online_room_tests PRIVATE seed_room)
  add_executable(seed_nat_traversal_tests tests/nat_traversal_tests.cpp)
  target_link_libraries(seed_nat_traversal_tests PRIVATE seed_room)
  add_library(seed_jp_cartridge STATIC ${JP_SHARDS}
    "${WORK_DIR}/generated/jp/dispatch_table.cpp" "${WORK_DIR}/generated/jp/symbol_map.cpp")
  target_include_directories(seed_jp_cartridge PRIVATE "${DEPS_DIR}/gbarecomp/src/armv4t" "${WORK_DIR}/generated/jp")
  add_executable(seed_jp_combat_driver tests/jp_combat_driver.cpp src/jp_combat_runtime.cpp)
  target_link_gbarecomp_runtime_stack(seed_jp_combat_driver seed_jp_cartridge)
  add_executable(seed_jp_rollback_tests tests/jp_rollback_tests.cpp src/jp_combat_runtime.cpp)
  target_link_gbarecomp_runtime_stack(seed_jp_rollback_tests seed_jp_cartridge)
  target_link_libraries(seed_jp_rollback_tests PRIVATE seed_gekkonet SDL3::SDL3)
  add_executable(seed_jp_netplay_peer tests/jp_netplay_peer.cpp src/jp_combat_runtime.cpp)
  target_link_gbarecomp_runtime_stack(seed_jp_netplay_peer seed_jp_cartridge)
  target_link_libraries(seed_jp_netplay_peer PRIVATE seed_transport)
  add_library(SeedJpCombat SHARED src/jp_combat_module.cpp src/jp_combat_runtime.cpp src/jp_online.cpp src/jp_asset_import.cpp)
  target_link_gbarecomp_runtime_stack(SeedJpCombat seed_jp_cartridge)
  target_link_libraries(SeedJpCombat PRIVATE seed_room)
  add_executable(seed_jp_online_module_peer tests/jp_online_module_peer.cpp)
  target_link_libraries(seed_jp_online_module_peer PRIVATE seed_transport seed_controls)
  add_dependencies(seed_jp_online_module_peer SeedJpCombat)
  add_dependencies(GundamSeedRecomp SeedJpCombat)
  if(MSVC)
    target_link_options(GundamSeedRecomp PRIVATE /STACK:16777216)
    target_link_options(seed_jp_combat_driver PRIVATE /STACK:16777216)
    target_link_options(seed_jp_online_module_peer PRIVATE /STACK:16777216)
  endif()
else()
  message(FATAL_ERROR "Generate the JP combat cartridge with build.ps1 before building the game host; the launcher can use SEED_BUILD_GAME=OFF")
endif()
endif()

if(WIN32)
  set(IMGUI_DIR "${DEPS_DIR}/imgui" CACHE PATH "Pinned Dear ImGui checkout")
  add_library(seed_imgui STATIC
    "${IMGUI_DIR}/imgui.cpp" "${IMGUI_DIR}/imgui_draw.cpp"
    "${IMGUI_DIR}/imgui_tables.cpp" "${IMGUI_DIR}/imgui_widgets.cpp"
    "${IMGUI_DIR}/misc/cpp/imgui_stdlib.cpp"
    "${IMGUI_DIR}/backends/imgui_impl_sdl3.cpp"
    "${IMGUI_DIR}/backends/imgui_impl_sdlrenderer3.cpp")
  target_include_directories(seed_imgui PUBLIC "${IMGUI_DIR}" "${IMGUI_DIR}/backends" "${IMGUI_DIR}/misc/cpp")
  target_link_libraries(seed_imgui PUBLIC SDL3::SDL3)
  add_library(seed_remap_ui STATIC src/in_game_remap.cpp src/online_lobby.cpp)
  target_link_libraries(seed_remap_ui PUBLIC seed_controls seed_imgui seed_links seed_profile)
  if(TARGET gbarecomp_runtime)
    target_link_libraries(gbarecomp_runtime PUBLIC seed_remap_ui)
  endif()
  add_library(seed_launcher_platform STATIC launcher/platform_win32.cpp launcher/settings.cpp)
  target_include_directories(seed_launcher_platform PUBLIC launcher)
  target_link_libraries(seed_launcher_platform PUBLIC bcrypt ole32 shell32 uuid)
  add_executable(GundamSeedLauncher WIN32 launcher/main.cpp)
  target_compile_definitions(GundamSeedLauncher PRIVATE SDL_MAIN_HANDLED)
  target_link_libraries(GundamSeedLauncher PRIVATE seed_imgui seed_launcher_platform seed_controls seed_links)
  target_sources(GundamSeedLauncher PRIVATE src/app.manifest)
  set(SEED_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app" CACHE PATH "Packaged runtime destination")
  add_custom_command(TARGET GundamSeedLauncher POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E make_directory "${SEED_APP_DIR}/licenses"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:GundamSeedLauncher>" "${SEED_APP_DIR}/GundamSeedLauncher.exe"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${IMGUI_DIR}/LICENSE.txt" "${SEED_APP_DIR}/licenses/Dear-ImGui.txt"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/SDL3/LICENSE.txt" "${SEED_APP_DIR}/licenses/SDL3.txt"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/config/controllerdb.txt" "${SEED_APP_DIR}/controllerdb.txt"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/config/controllerdb-LICENSE.txt" "${SEED_APP_DIR}/licenses/SDL-GameControllerDB.txt")
  if(TARGET GundamSeedRecomp)
    add_custom_command(TARGET GundamSeedRecomp POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E make_directory "${SEED_APP_DIR}/licenses"
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:GundamSeedRecomp>" "${SEED_APP_DIR}/GundamSeedRecomp.exe"
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/gbarecomp/LICENSE" "${SEED_APP_DIR}/licenses/GBARecomp.txt"
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/gbarecomp/external/arm-recomp-core/LICENSE" "${SEED_APP_DIR}/licenses/arm-recomp-core.txt"
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/config/controllerdb.txt" "${SEED_APP_DIR}/controllerdb.txt"
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/config/controllerdb-LICENSE.txt" "${SEED_APP_DIR}/licenses/SDL-GameControllerDB.txt")
  endif()
  add_executable(seed_launcher_tests tests/launcher_tests.cpp)
  target_link_libraries(seed_launcher_tests PRIVATE seed_launcher_platform)
endif()

foreach(SEED_RUNTIME_TARGET GundamSeedRecomp GundamSeedLauncher seed_sdl3_host_tests seed_jp_combat_driver seed_jp_rollback_tests seed_jp_netplay_peer seed_jp_online_module_peer seed_controls_tests seed_join_code_tests seed_invite_window_tests seed_nat_probe seed_nat_traversal_tests seed_in_game_remap_tests seed_online_lobby_tests seed_online_room_tests seed_bios_fast_set_tests SeedJpCombat)
  if(TARGET ${SEED_RUNTIME_TARGET})
    add_custom_command(TARGET ${SEED_RUNTIME_TARGET} POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/config/controllerdb.txt" "$<TARGET_FILE_DIR:${SEED_RUNTIME_TARGET}>/controllerdb.txt")
    add_custom_command(TARGET ${SEED_RUNTIME_TARGET} POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:SDL3::SDL3>" "$<TARGET_FILE_DIR:${SEED_RUNTIME_TARGET}>/SDL3.dll")
  endif()
endforeach()
if(TARGET GundamSeedLauncher)
  add_custom_command(TARGET GundamSeedLauncher POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:SDL3::SDL3>" "${SEED_APP_DIR}/SDL3.dll")
endif()
if(TARGET SeedJpCombat)
  add_custom_command(TARGET SeedJpCombat POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E make_directory "${SEED_APP_DIR}"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:SeedJpCombat>" "${SEED_APP_DIR}/SeedJpCombat.dll"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:SDL3::SDL3>" "${SEED_APP_DIR}/SDL3.dll"
    COMMAND ${CMAKE_COMMAND} -E make_directory "${SEED_APP_DIR}/licenses"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/GekkoNet/LICENSE" "${SEED_APP_DIR}/licenses/GekkoNet.txt"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/autopunch/LICENSE" "${SEED_APP_DIR}/licenses/AutoPunch.txt"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPS_DIR}/GekkoNet/GekkoLib/thirdparty/zpp/LICENSE" "${SEED_APP_DIR}/licenses/GekkoNet-zpp.txt")
endif()
