cmake_minimum_required(VERSION 3.22)
project(Bombo VERSION 1.0.1 LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# JUCE via FetchContent, pinned tag. No system install required.
# Override with -DBOMBO_USE_SYSTEM_JUCE=ON to use find_package instead.
option(BOMBO_USE_SYSTEM_JUCE "Use system-installed JUCE via find_package" OFF)

if(BOMBO_USE_SYSTEM_JUCE)
    find_package(JUCE CONFIG REQUIRED)
else()
    include(FetchContent)
    FetchContent_Declare(
        JUCE
        GIT_REPOSITORY https://github.com/juce-framework/JUCE.git
        GIT_TAG        8.0.12
        GIT_SHALLOW    TRUE)
    FetchContent_MakeAvailable(JUCE)
endif()

# CLAP support via clap-juce-extensions (free-audio). Builds a CLAP target
# alongside the juce_add_plugin formats — CLAP is NOT listed in FORMATS;
# clap_juce_extensions_plugin() below wires it up from the existing JUCE
# plugin target. Pulls its own clap/clap-helpers submodules via FetchContent.
# Pinned to a main commit (post-0.26.0) for JUCE 8.0.11+ compatibility: the
# 0.26.0 tag still includes juce_LegacyAudioParameter.cpp, which JUCE 8.0.12
# relocated to the juce_audio_processors_headless module (clap-juce PR #169).
include(FetchContent)
FetchContent_Declare(
    clap-juce-extensions
    GIT_REPOSITORY https://github.com/free-audio/clap-juce-extensions.git
    GIT_TAG        e8de9e8571626633b8541a54c2406fccc4272767)
FetchContent_MakeAvailable(clap-juce-extensions)

# AU is macOS-only; JUCE silently drops it on other platforms.
juce_add_plugin(Bombo
    COMPANY_NAME "Hyperfocus DSP"
    COMPANY_WEBSITE "https://hyperfocusdsp.com"
    COMPANY_EMAIL "hello@hyperfocusdsp.com"
    PLUGIN_MANUFACTURER_CODE Hfds
    PLUGIN_CODE Bomb
    BUNDLE_ID com.hyperfocusdsp.bombo
    FORMATS VST3 AU Standalone
    PRODUCT_NAME "Bombo"
    IS_SYNTH TRUE
    NEEDS_MIDI_INPUT TRUE
    NEEDS_MIDI_OUTPUT FALSE
    IS_MIDI_EFFECT FALSE
    EDITOR_WANTS_KEYBOARD_FOCUS TRUE
    COPY_PLUGIN_AFTER_BUILD FALSE
    VST3_CATEGORIES "Instrument" "Drum"
    AU_MAIN_TYPE "kAudioUnitType_MusicDevice"
    DESCRIPTION "Half kick instrument, half 1992 BBS. One plugin.")

# Wire the CLAP build off the existing Bombo JUCE target. Produces
# build/Bombo_artefacts/<cfg>/CLAP/Bombo.clap. CLAP_FEATURES drives the
# CLAP plugin-category metadata (Bombo is a drum/kick instrument).
clap_juce_extensions_plugin(TARGET Bombo
    CLAP_ID "com.hyperfocusdsp.bombo"
    CLAP_FEATURES instrument drum drum-machine)

juce_add_binary_data(BomboResources
    SOURCES
        Resources/Layout.json
        Resources/Fonts/AllertaStencil-Regular.ttf
        Resources/Themes/bandw.json
        Resources/Themes/nightrun.json
        Resources/Themes/vault.json
        Resources/Themes/matrix.json
        Resources/Themes/cyber.json
        Resources/Themes/plasma.json
        Resources/Themes/fallout.json
        Resources/Presets/00_hardtech.json
        Resources/Presets/01_reverze.json
        Resources/Presets/02_juicy.json
        Resources/Presets/03_chunky.json
        Resources/Presets/04_crusher.json
        Resources/Presets/05_hammer.json
        Resources/Presets/06_hardkick.json
        Resources/Presets/07_horror.json
        Resources/Presets/08_pew.json
        Resources/Presets/09_superwet.json
        Resources/Samples/kick_01.wav
        Resources/Samples/kick_02.wav
        Resources/Samples/kick_03.wav
        Resources/Samples/kick_04.wav
        Resources/Samples/kick_05.wav
        Resources/Samples/kick_06.wav
        Resources/Textures/chassis_overlay.png
        Resources/Textures/fallout_chassis.png
        Resources/Textures/fallout_header.png
        Resources/Textures/fallout_rack_1.png
        Resources/Textures/fallout_rack_2.png
        Resources/Textures/fallout_rack_3.png
        Resources/Textures/fallout_rack_4.png
        Resources/Textures/fallout_rack_5.png
        Resources/Textures/fallout_rack_6.png
        Resources/Textures/fallout_rack_7.png
        Resources/Textures/fallout_knob.png
        Resources/Textures/fallout_knob_out.png
        Resources/Textures/bombo_logo.png
        Resources/Audio/game_propulsion.wav)

target_sources(Bombo
    PRIVATE
        Source/PluginProcessor.cpp
        Source/PluginProcessor.h
        Source/PluginEditor.cpp
        Source/PluginEditor.h
        Source/X11CompositorClaim.cpp
        Source/Parameters.h
        Source/GUI/Colours.h
        Source/GUI/CrtScreen.h
        Source/GUI/Theme/Palette.h
        Source/GUI/Theme/ThemeProvider.h
        Source/GUI/Theme/ThemeProvider.cpp
        Source/GUI/Theme/ThemeLoader.h
        Source/GUI/Theme/ThemeLoader.cpp
        Source/GUI/Theme/ThemedComponent.h
        Source/State/PersistentState.h
        Source/State/PersistentState.cpp
        Source/State/PresetBank.h
        Source/State/PresetBank.cpp
        Source/GUI/Fonts.h
        Source/GUI/Fonts.cpp
        Source/GUI/BalanceFader.h
        Source/GUI/BomboLookAndFeel.h
        Source/GUI/BpmDisplay.h
        Source/GUI/DiceButton.h
        Source/GUI/FaceplatePanel.h
        Source/GUI/FaceplatePanel.cpp
        Source/GUI/HeaderRenderer.h
        Source/GUI/HeaderRenderer.cpp
        Source/GUI/ChassisRenderer.h
        Source/GUI/ChassisRenderer.cpp
        Source/GUI/ThemeTileStrip.h
        Source/GUI/ThemeTileStrip.cpp
        Source/GUI/BomboKnob.h
        Source/GUI/SampleSlotWidget.h
        Source/GUI/WaveBuffer.h
        Source/GUI/ScopeComponent.h
        Source/GUI/ScopeComponent.cpp
        Source/GUI/PresetBarComponent.h
        Source/GUI/PresetBarComponent.cpp
        Source/GUI/BBS/BBSComponent.h
        Source/GUI/BBS/BBSComponent.cpp
        Source/GUI/BBS/ProgressionManager.h
        Source/GUI/BBS/ProgressionManager.cpp
        Source/GUI/BBS/BoomFeed.h
        Source/GUI/BBS/BoomFeed.cpp
        Source/GUI/BBS/BombImpactGame.h
        Source/GUI/BBS/BombImpactGame.cpp
        Source/GUI/BBS/Game/Palette.cpp
        Source/GUI/BBS/Game/Framebuffer.cpp
        Source/GUI/BBS/Game/Entities.cpp
        Source/GUI/BBS/Game/Waves.cpp
        Source/GUI/BBS/Game/Shop.cpp
        Source/GUI/BBS/Game/Drops.cpp
        Source/GUI/BBS/Game/HighScores.cpp
        Source/GUI/BBS/Game/Discovery.cpp
        Source/GUI/BBS/Game/Audio.cpp
        Source/GUI/BBS/Game/Game.cpp
        Source/GUI/BBS/Game/Effects.cpp
        Source/GUI/Nose/NoseComponent.h
        Source/GUI/Nose/NoseComponent.cpp
        Source/GUI/BombShape.h
        Source/GUI/BombShape.cpp
        Source/GUI/LayoutManager.h
        Source/GUI/LayoutManager.cpp
        Source/GUI/LayoutEditOverlay.h
        Source/GUI/LayoutEditOverlay.cpp
        Source/DSP/Oscillators.h
        Source/DSP/Envelopes.h
        Source/DSP/ClickGen.h
        Source/DSP/NoiseGen.h
        Source/DSP/SampleSlot.h
        Source/DSP/VoiceClip.h
        Source/DSP/BombVoice.h
        Source/DSP/VoiceManager.h
        Source/DSP/VoiceManager.cpp
        Source/DSP/BiquadFilter.h
        Source/DSP/StereoFinalizer.h
        Source/DSP/Delay.h
        Source/DSP/FdnReverb.h
        Source/DSP/Ducker.h
        Source/DSP/MultibandLimiter.h
        Source/DSP/MasterBus.h
        Source/DSP/RumbleChain.h
        Source/Bounce/OfflineBouncer.h
        Source/Bounce/OfflineBouncer.cpp)

target_compile_definitions(Bombo
    PUBLIC
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
        JUCE_VST3_CAN_REPLACE_VST2=0
        # Linux X11: enable XRender so JUCE selects an ARGB visual when
        # setOpaque(false) is set on the top-level window. Required for
        # the bomb-tail corner wedges to be truly transparent.
        # (Tested removing this to fix DAW embedding — it did NOT change the
        # editor's parentage, only broke the transparent-corner rendering, so
        # it is kept. The embed failure is unrelated to the X11 visual depth.)
        JUCE_USE_XRENDER=1
        # Disable JACK on Linux. PipeWire's JACK emulation silently
        # "succeeds" (device object created, no error returned) but
        # never fires the processBlock callback. ALSA via pipewire-alsa
        # is the reliable path on every PipeWire system. Users who
        # specifically need JACK can re-enable via -DBOMBO_JACK=ON.
        $<$<AND:$<BOOL:${UNIX}>,$<NOT:$<BOOL:${APPLE}>>,$<NOT:$<BOOL:${BOMBO_JACK}>>>:JUCE_JACK=0>)

# LTO is a big build-time RAM hog (lto1 can take >4GB on the
# Standalone link with -flto). Default ON for release builds; flip
# OFF on memory-limited boxes via -DBOMBO_LTO=OFF.
option(BOMBO_LTO "Link with -flto (juce_recommended_lto_flags)" ON)

target_link_libraries(Bombo
    PRIVATE
        BomboResources
        juce::juce_audio_processors
        juce::juce_audio_utils
        juce::juce_audio_devices
        juce::juce_audio_formats
        juce::juce_dsp
        juce::juce_gui_basics
        juce::juce_graphics
        juce::juce_core
        juce::juce_data_structures
        juce::juce_events
    PUBLIC
        juce::juce_recommended_config_flags)
if(BOMBO_LTO)
    target_link_libraries(Bombo PUBLIC juce::juce_recommended_lto_flags)
endif()

# X11 is needed for the compositor-selection claim that bridges JUCE's
# transparency check on Hyprland/XWayland (see Source/X11CompositorClaim.cpp).
if(UNIX AND NOT APPLE)
    find_package(X11 REQUIRED)
    target_link_libraries(Bombo PRIVATE ${X11_LIBRARIES})
    target_include_directories(Bombo PRIVATE ${X11_INCLUDE_DIR})
endif()

# ── v2 Game build flag ────────────────────────────────────────────
# Default ON: v2 chunky-pixel game is the shipping path (KVRDC).
# Opt out with -DBOMBO_GAME_V2=OFF to fall back to v1 BombImpactGame (ASCII).
option(BOMBO_GAME_V2 "Enable v2 chunky-pixel game (replaces BombImpactGame)" ON)
if(BOMBO_GAME_V2)
    target_compile_definitions(Bombo PRIVATE BOMBO_GAME_V2=1)
endif()

# ── DSP unit tests ────────────────────────────────────────────────
# JUCE UnitTestRunner. Builds a console exe that runs every registered
# UnitTest subclass; ctest treats nonzero exit as failure.
option(BOMBO_BUILD_TESTS "Build Bombo DSP unit tests" ON)
if(BOMBO_BUILD_TESTS)
    enable_testing()
    juce_add_console_app(Bombo_Tests
        PRODUCT_NAME "Bombo_Tests")
    target_sources(Bombo_Tests PRIVATE
        tests/RunTests.cpp
        tests/PaletteTests.cpp
        tests/VoiceStealingTests.cpp
        tests/StateRoundTripTests.cpp
        tests/PresetDeterminismTests.cpp
        tests/PreGamePresetStashTests.cpp
        tests/BbsPersistenceTests.cpp
        tests/BBSProgressionTests.cpp
        tests/BombShapeTests.cpp
        tests/OfflineBouncerTests.cpp
        tests/BoomFeedTests.cpp
        tests/GamePaletteTests.cpp
        tests/GameFramebufferTests.cpp
        tests/GameEntitiesTests.cpp
        tests/GameWavesTests.cpp
        tests/GameShopTests.cpp
        tests/GameDropsTests.cpp
        tests/GameEffectsTests.cpp
        tests/GameHighScoresTests.cpp
        tests/GameRumblrTests.cpp
        tests/GameStateTests.cpp
        tests/GameBalanceSimTests.cpp
        tests/GameScoringTests.cpp
        tests/GameLoopTests.cpp
        tests/GameFlowTests.cpp
        tests/GameInputTests.cpp
        tests/GameDiscoveryTests.cpp
        tests/GameAudioTests.cpp
        tests/MidiLearnTests.cpp
        tests/DuckRoutingTests.cpp
        Source/GUI/BBS/Game/Palette.cpp
        Source/GUI/BBS/Game/Framebuffer.cpp
        Source/GUI/BBS/Game/Entities.cpp
        Source/GUI/BBS/Game/Waves.cpp
        Source/GUI/BBS/Game/Shop.cpp
        Source/GUI/BBS/Game/Drops.cpp
        Source/GUI/BBS/Game/HighScores.cpp
        Source/GUI/BBS/Game/Discovery.cpp
        Source/GUI/BBS/Game/Audio.cpp
        Source/GUI/BBS/Game/Game.cpp
        Source/GUI/BBS/Game/Effects.cpp
        Source/GUI/BBS/ProgressionManager.cpp
        Source/GUI/BBS/BoomFeed.cpp
        Source/GUI/Theme/ThemeProvider.cpp
        Source/GUI/Theme/ThemeLoader.cpp
        Source/State/PersistentState.cpp
        Source/State/PresetBank.cpp
        Source/GUI/BombShape.cpp
        Source/DSP/VoiceManager.cpp)
    target_include_directories(Bombo_Tests PRIVATE Source tests)
    target_compile_definitions(Bombo_Tests PRIVATE
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
        BOMBO_GAME_TEST_HOOKS=1
        $<$<BOOL:${BOMBO_GAME_V2}>:BOMBO_GAME_V2=1>)
    target_link_libraries(Bombo_Tests
        PRIVATE
            BomboResources
            juce::juce_core
            juce::juce_data_structures
            juce::juce_events
            juce::juce_graphics
            juce::juce_dsp
            juce::juce_audio_basics
            juce::juce_audio_formats
            juce::juce_audio_processors
        PUBLIC
            juce::juce_recommended_config_flags)
    if(BOMBO_LTO)
        target_link_libraries(Bombo_Tests PUBLIC juce::juce_recommended_lto_flags)
    endif()
    add_test(NAME bombo_unit_tests COMMAND Bombo_Tests)

    # ── Headless balance sim (Task 25 / spec §13.3) ───────────────────
    # Drives the assembled v2 Game with a heuristic AutoPlayer over many
    # FORCED-seed runs and reports per-wave survival / boss-completion to
    # build/sim-results.json. Links the MINIMAL game module set Game.cpp
    # actually needs (no Audio/Discovery/BBS/processor deps — those reach
    # the game only through null-safe std::function seams). The forced-seed
    # entry point is gated behind BOMBO_GAME_TEST_HOOKS.
    juce_add_console_app(Bombo_BalanceSim
        PRODUCT_NAME "Bombo_BalanceSim")
    target_sources(Bombo_BalanceSim PRIVATE
        tests/GameBalanceSim.cpp
        Source/GUI/BBS/Game/Palette.cpp
        Source/GUI/BBS/Game/Framebuffer.cpp
        Source/GUI/BBS/Game/Entities.cpp
        Source/GUI/BBS/Game/Waves.cpp
        Source/GUI/BBS/Game/Shop.cpp
        Source/GUI/BBS/Game/Drops.cpp
        Source/GUI/BBS/Game/Effects.cpp
        Source/GUI/BBS/Game/HighScores.cpp
        Source/GUI/BBS/Game/Game.cpp)
    target_include_directories(Bombo_BalanceSim PRIVATE Source)
    target_compile_definitions(Bombo_BalanceSim PRIVATE
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
        BOMBO_GAME_TEST_HOOKS=1
        BOMBO_HEADLESS_SIM=1
        $<$<BOOL:${BOMBO_GAME_V2}>:BOMBO_GAME_V2=1>)
    target_link_libraries(Bombo_BalanceSim
        PRIVATE
            juce::juce_core
            juce::juce_events
            juce::juce_data_structures
            juce::juce_graphics
            juce::juce_gui_basics
        PUBLIC
            juce::juce_recommended_config_flags)

    find_package(Python3 COMPONENTS Interpreter)
    if(Python3_Interpreter_FOUND)
        add_test(NAME bombo_ascii_lint
            COMMAND ${Python3_EXECUTABLE}
                    ${CMAKE_CURRENT_SOURCE_DIR}/tools/check-no-utf8-strings.py)
        # Also run the lint at BUILD TIME, not just under ctest. A user-
        # facing string with a UTF-8 byte produces silent mojibake at
        # render time (juce::String(const char*) rejects bytes > 0x7F)
        # — catching it at build time is much cheaper than discovering
        # it via an image-attached bug report after the fact. The custom
        # target is wired as a dependency of Bombo so any Bombo build
        # (VST3, Standalone, Tests) fails fast if a literal regresses.
        add_custom_target(bombo_ascii_lint_build
            COMMAND ${Python3_EXECUTABLE}
                    ${CMAKE_CURRENT_SOURCE_DIR}/tools/check-no-utf8-strings.py
            COMMENT "Checking string literals for non-ASCII bytes"
            VERBATIM)
        add_dependencies(Bombo bombo_ascii_lint_build)
    endif()
endif()
