cmake_minimum_required(VERSION 3.24)
project(Blaze VERSION 0.1.0 LANGUAGES C)
include(CTest)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(MSVC)
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
    add_compile_definitions(_CRT_SECURE_NO_WARNINGS=)
endif()
get_filename_component(BLAZE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
set(BLAZE_ASSET_DIRECTORY "${BLAZE_ROOT}" CACHE PATH "Read-only data used by checks and runtime packaging")
option(BLAZE_BUILD_APPLICATION "Build the real game application" ON)
set(default_platform SDL3)
if(WIN32)
    set(default_platform WIN32)
endif()
set(BLAZE_PLATFORM "${default_platform}" CACHE STRING "Application backend: WIN32 or SDL3")
set_property(CACHE BLAZE_PLATFORM PROPERTY STRINGS WIN32 SDL3)
if(NOT BLAZE_PLATFORM MATCHES "^(WIN32|SDL3)$")
    message(FATAL_ERROR "Unknown BLAZE_PLATFORM")
endif()
if(BLAZE_BUILD_APPLICATION AND NOT WIN32 AND BLAZE_PLATFORM STREQUAL "WIN32")
    message(FATAL_ERROR "The WIN32 comparison backend requires Windows; select SDL3.")
endif()

# Explicit native-only sources: the private recovery tree is never added.
add_library(blaze_game STATIC
    platform/files.c game/assets.c game/audio.c game/music.c game/draw.c game/rotate.c game/quad.c
    game/app.c game/level.c game/player.c game/world.c game/combat.c game/weapons.c
    game/actors.c game/random.c game/damage.c game/game_over.c game/stage_clear.c)
target_include_directories(blaze_game PUBLIC include)
if(UNIX)
    target_link_libraries(blaze_game PUBLIC m)
endif()
if(MSVC)
    target_compile_options(blaze_game PRIVATE /W4)
else()
    target_compile_options(blaze_game PRIVATE -Wall -Wextra -Wpedantic)
endif()

# Shared native platform state, separate from window/device backends.
add_library(blaze_settings STATIC platform/settings.c platform/controls.c)
target_include_directories(blaze_settings PUBLIC platform)
target_link_libraries(blaze_settings PUBLIC blaze_game)

# SDL_GetBasePath points at Contents/Resources inside a macOS app.
set(BLAZE_RUNTIME_ASSETS "${CMAKE_BINARY_DIR}/bin")
set(BLAZE_INSTALL_ASSETS ".")
set(BLAZE_INSTALL_LIBRARIES ".")
if(APPLE AND BLAZE_BUILD_APPLICATION)
    set(BLAZE_RUNTIME_ASSETS "${CMAKE_BINARY_DIR}/bin/Blaze.app/Contents/Resources")
    set(BLAZE_INSTALL_ASSETS "Blaze.app/Contents/Resources")
    set(BLAZE_INSTALL_LIBRARIES "Blaze.app/Contents/Frameworks")
endif()
# Committed, verified resources; building never reads the original PE.
include(resources/verify.cmake)
file(MAKE_DIRECTORY "${BLAZE_RUNTIME_ASSETS}/resources")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/bin/resources")
foreach(name rop.bin trig.bin blaze.ico)
    configure_file("resources/${name}" "${BLAZE_RUNTIME_ASSETS}/resources/${name}" COPYONLY)
endforeach()
if(WIN32 AND (BLAZE_BUILD_APPLICATION OR BUILD_TESTING))
    enable_language(RC)
    configure_file(platform/windows.rc.in "${CMAKE_CURRENT_BINARY_DIR}/windows.rc" @ONLY)
    set(blaze_window_resource "${CMAKE_CURRENT_BINARY_DIR}/windows.rc")
    add_library(blaze_windows_music STATIC platform/windows_music.c)
    target_include_directories(blaze_windows_music PUBLIC platform)
    target_link_libraries(blaze_windows_music PUBLIC blaze_game winmm user32)
    add_library(blaze_windows_audio STATIC platform/windows_audio.c)
    target_include_directories(blaze_windows_audio PUBLIC platform)
    target_link_libraries(blaze_windows_audio PUBLIC blaze_windows_music)
endif()
if(BLAZE_BUILD_APPLICATION)
    if(BLAZE_PLATFORM STREQUAL "SDL3")
        include(cmake/sdl.cmake)
        include(cmake/midi.cmake)
        add_library(blaze_sdl_pcm STATIC platform/sdl_pcm.c)
        target_include_directories(blaze_sdl_pcm PUBLIC platform)
        target_link_libraries(blaze_sdl_pcm PUBLIC blaze_game SDL3::SDL3-static)
        add_library(blaze_sdl_audio STATIC platform/sdl_audio.c)
        add_library(blaze_sdl_controls STATIC platform/sdl_controls.c platform/sdl_paths.c)
        target_include_directories(blaze_sdl_controls PUBLIC platform)
        target_link_libraries(blaze_sdl_controls PUBLIC blaze_settings SDL3::SDL3-static)
        add_library(blaze_sdl_music STATIC platform/sdl_music.c)
        target_include_directories(blaze_sdl_music PUBLIC platform)
        target_link_libraries(blaze_sdl_music PUBLIC blaze_game SDL3::SDL3-static libfluidsynth)
        target_link_libraries(blaze_sdl_audio PUBLIC blaze_sdl_pcm blaze_sdl_music)
        add_executable(blaze-native platform/sdl.c ${blaze_window_resource})
        target_link_libraries(blaze-native PRIVATE blaze_sdl_audio blaze_sdl_controls)
    else()
        add_executable(blaze-native platform/windows.c "${CMAKE_CURRENT_BINARY_DIR}/windows.rc")
        target_link_libraries(blaze-native PRIVATE blaze_windows_audio)
    endif()
    target_include_directories(blaze-native PRIVATE platform)
    target_link_libraries(blaze-native PRIVATE blaze_settings)
    if(NOT BLAZE_PLATFORM STREQUAL "SDL3")
        target_link_libraries(blaze-native PRIVATE user32 gdi32)
    endif()
    set_target_properties(blaze-native PROPERTIES OUTPUT_NAME blaze RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
    if(WIN32 AND BLAZE_PLATFORM STREQUAL "SDL3")
        set_target_properties(blaze-native PROPERTIES WIN32_EXECUTABLE TRUE)
    endif()
    foreach(config DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
        set_target_properties(blaze-native PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${config} "${CMAKE_BINARY_DIR}/bin")
    endforeach()
    if(APPLE)
        target_sources(blaze-native PRIVATE resources/blaze.icns)
        set_source_files_properties(resources/blaze.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
        set_target_properties(blaze-native PROPERTIES MACOSX_BUNDLE TRUE OUTPUT_NAME Blaze
            MACOSX_BUNDLE_ICON_FILE blaze.icns
            MACOSX_BUNDLE_GUI_IDENTIFIER org.blaze-decomp.blaze
            MACOSX_BUNDLE_BUNDLE_NAME Blaze
            MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
            BUILD_RPATH "@executable_path/../Frameworks" INSTALL_RPATH "@executable_path/../Frameworks")
    elseif(UNIX)
        set_target_properties(blaze-native PROPERTIES BUILD_RPATH "$ORIGIN" INSTALL_RPATH "$ORIGIN")
    endif()
    # Share immutable assets in build trees, never hard-link writable INIs.
    foreach(dir dar dat midi se)
        file(MAKE_DIRECTORY "${BLAZE_RUNTIME_ASSETS}/${dir}")
        file(GLOB runtime_assets "${BLAZE_ASSET_DIRECTORY}/${dir}/*")
        foreach(asset IN LISTS runtime_assets)
            if(NOT asset MATCHES "\\.[iI][nN][iI]$")
                get_filename_component(name "${asset}" NAME)
                if(NOT EXISTS "${BLAZE_RUNTIME_ASSETS}/${dir}/${name}")
                    file(CREATE_LINK "${asset}" "${BLAZE_RUNTIME_ASSETS}/${dir}/${name}" COPY_ON_ERROR)
                endif()
            endif()
        endforeach()
    endforeach()
    foreach(name Blz.ini BlzScr.ini)
        if(NOT EXISTS "${BLAZE_RUNTIME_ASSETS}/dat/${name}")
            configure_file("resources/defaults/${name}" "${BLAZE_RUNTIME_ASSETS}/dat/${name}" COPYONLY)
        endif()
    endforeach()
    install(TARGETS blaze-native RUNTIME DESTINATION . COMPONENT Runtime BUNDLE DESTINATION . COMPONENT Runtime)
    install(FILES resources/rop.bin resources/trig.bin DESTINATION "${BLAZE_INSTALL_ASSETS}/resources" COMPONENT Runtime)
    install(DIRECTORY "${BLAZE_ASSET_DIRECTORY}/dar" "${BLAZE_ASSET_DIRECTORY}/midi"
        "${BLAZE_ASSET_DIRECTORY}/se" "${BLAZE_ASSET_DIRECTORY}/html" "${BLAZE_ASSET_DIRECTORY}/html_en"
        DESTINATION "${BLAZE_INSTALL_ASSETS}" COMPONENT Runtime)
    install(DIRECTORY "${BLAZE_ASSET_DIRECTORY}/dat/" DESTINATION "${BLAZE_INSTALL_ASSETS}/dat" COMPONENT Runtime FILES_MATCHING PATTERN "*.dat")
    # Package pristine defaults, never the player's writable root INIs.
    install(FILES resources/defaults/Blz.ini resources/defaults/BlzScr.ini DESTINATION "${BLAZE_INSTALL_ASSETS}/dat" COMPONENT Runtime)
    install(FILES "${BLAZE_ROOT}/README.md" "${BLAZE_ROOT}/THIRD_PARTY_NOTICES.md"
        "${BLAZE_ROOT}/docs/TESTING.md" "${BLAZE_ROOT}/docs/DISTRIBUTION.md"
        DESTINATION "${BLAZE_INSTALL_ASSETS}" COMPONENT Runtime)
    if(BLAZE_PLATFORM STREQUAL "SDL3")
        install(FILES third_party/SDL3-LICENSE.txt DESTINATION "${BLAZE_INSTALL_ASSETS}" COMPONENT Runtime)
    endif()
endif()
if(BUILD_TESTING)
    file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/bin/resources")
    foreach(name rop.bin trig.bin)
        configure_file("resources/${name}" "${CMAKE_BINARY_DIR}/bin/resources/${name}" COPYONLY)
    endforeach()
    add_executable(settings-check tests/platform/settings.c)
    target_link_libraries(settings-check PRIVATE blaze_settings)
    file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/test-data/settings")
    add_test(NAME native-settings COMMAND settings-check "${CMAKE_BINARY_DIR}/test-data/settings")
    set(test_assets "${CMAKE_BINARY_DIR}/fixtures")
    if(TARGET SDL3::SDL3-static)
        add_executable(sdl-presentation-check tests/platform/sdl.c ${blaze_window_resource})
        target_link_libraries(sdl-presentation-check PRIVATE blaze_settings blaze_sdl_audio blaze_sdl_controls)
        set_target_properties(sdl-presentation-check PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<0:>")
        file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/controls-check")
        add_test(NAME sdl-presentation-input COMMAND sdl-presentation-check "${test_assets}" "${CMAKE_BINARY_DIR}/controls-check")
        add_executable(sdl-pcm-check tests/platform/sdl_pcm.c)
        target_link_libraries(sdl-pcm-check PRIVATE blaze_game SDL3::SDL3-static)
        foreach(mode stream dummy device)
            add_test(NAME sdl-pcm-${mode} COMMAND sdl-pcm-check "${BLAZE_ASSET_DIRECTORY}" --${mode})
            set_tests_properties(sdl-pcm-${mode} PROPERTIES TIMEOUT 15)
        endforeach()
        set_tests_properties(sdl-pcm-device PROPERTIES SKIP_RETURN_CODE 77)
        add_executable(sdl-music-check tests/platform/sdl_music.c)
        target_include_directories(sdl-music-check PRIVATE platform)
        target_link_libraries(sdl-music-check PRIVATE blaze_game SDL3::SDL3-static libfluidsynth)
        set_target_properties(sdl-music-check PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<0:>")
        file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/midi-check")
        add_test(NAME sdl-midi-lifecycle COMMAND sdl-music-check "${CMAKE_BINARY_DIR}/midi-check" "${BLAZE_ASSET_DIRECTORY}")
        set_tests_properties(sdl-midi-lifecycle PROPERTIES TIMEOUT 20)
        if(WIN32)
            target_link_libraries(sdl-presentation-check PRIVATE user32 gdi32)
        endif()
    endif()
    # One reusable fixture tree shares immutable data, with clean INI defaults.
    # Developer score/unlock/options changes cannot affect test expectations.
    foreach(dir dar dat se midi)
        file(MAKE_DIRECTORY "${test_assets}/${dir}")
        file(GLOB assets "${BLAZE_ASSET_DIRECTORY}/${dir}/*")
        foreach(asset IN LISTS assets)
            if(NOT asset MATCHES "\\.[iI][nN][iI]$")
                get_filename_component(name "${asset}" NAME)
                if(NOT EXISTS "${test_assets}/${dir}/${name}")
                    file(CREATE_LINK "${asset}" "${test_assets}/${dir}/${name}" COPY_ON_ERROR)
                endif()
            endif()
        endforeach()
    endforeach()
    configure_file(resources/defaults/Blz.ini "${test_assets}/dat/Blz.ini" COPYONLY)
    configure_file(resources/defaults/BlzScr.ini "${test_assets}/dat/BlzScr.ini" COPYONLY)
    foreach(pair "native-startup-check;native_startup" "audio-pause-check;audio_pause" "menu-check;menus")
        list(GET pair 0 target)
        list(GET pair 1 file)
        add_executable(${target} "tests/gameplay/${file}.c")
        target_link_libraries(${target} PRIVATE blaze_game)
    endforeach()
    add_test(NAME native-startup-lifecycle COMMAND native-startup-check "${test_assets}" "${CMAKE_BINARY_DIR}/bin/resources/rop.bin")
    add_test(NAME native-audio-pause COMMAND audio-pause-check "${test_assets}" "${CMAKE_BINARY_DIR}/bin/resources/rop.bin")
    add_test(NAME native-menus COMMAND menu-check "${test_assets}" "${CMAKE_BINARY_DIR}/bin/resources/rop.bin")
    if(WIN32)
        add_executable(windows-audio-check tests/platform/windows_audio.c)
        target_link_libraries(windows-audio-check PRIVATE blaze_windows_audio)
        add_test(NAME windows-audio-transport COMMAND windows-audio-check "${test_assets}")
        set_tests_properties(windows-audio-transport PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30)
        add_executable(windows-presentation-check tests/platform/windows_presentation.c "${CMAKE_CURRENT_BINARY_DIR}/windows.rc")
        target_include_directories(windows-presentation-check PRIVATE platform)
        target_link_libraries(windows-presentation-check PRIVATE blaze_settings blaze_windows_audio user32 gdi32)
        add_test(NAME windows-presentation COMMAND windows-presentation-check "${test_assets}" "${CMAKE_BINARY_DIR}/bin/resources/rop.bin")
    endif()
endif()
