cmake_minimum_required(VERSION 3.19)
project(reaper_reasampler LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# ---------------------------------------------------------------------------
# Vendored dependencies — add as git submodules (see README):
#   git submodule add https://github.com/justinfrankel/reaper-sdk vendor/reaper-sdk
#   git submodule add https://github.com/justinfrankel/WDL        vendor/WDL
# ---------------------------------------------------------------------------
set(SDK_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/reaper-sdk/sdk)
set(WDL_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/WDL/WDL)
set(SWELL   ${WDL_INC}/swell)

# ---------------------------------------------------------------------------
# 1) Pure model library — NO REAPER, NO SWELL. Builds & tests anywhere.
#    The sampler's heart: Sample metadata + BankIndex (Milestone 1).
# ---------------------------------------------------------------------------
add_library(bank_model STATIC src/bank_model.cpp)
target_include_directories(bank_model PUBLIC src)

# ---------------------------------------------------------------------------
# 2) Pure peaks library — NO REAPER, NO SWELL. Waveform min/max thumbnails from
#    raw PCM (Milestone 2). A sibling pure lib, kept distinct from bank_model.
# ---------------------------------------------------------------------------
add_library(peaks STATIC src/peaks.cpp)
target_include_directories(peaks PUBLIC src)

# ---------------------------------------------------------------------------
# 2b) Pure capture-path arithmetic — NO REAPER, NO SWELL. Bank-folder / unique
#     file-name / project-relative path derivation for the capture shell (M3).
#     Split out so the fiddly path logic is unit-tested outside the DAW.
# ---------------------------------------------------------------------------
add_library(capture_paths STATIC src/capture_paths.cpp)
target_include_directories(capture_paths PUBLIC src)

# ---------------------------------------------------------------------------
# 2c) Pure bank-grid layout — NO REAPER, NO SWELL. Grid tiling math (panel WxH +
#     cell size + N -> cell rects, wrapping, partial last row) and the thumbnail
#     cache key for the docked bank_panel (M5). Split out so the layout logic is
#     unit-tested outside the DAW; the panel shell (SWELL/LICE/PCM) is DAW-verified.
# ---------------------------------------------------------------------------
add_library(bank_grid STATIC src/bank_grid.cpp)
target_include_directories(bank_grid PUBLIC src)

# ---------------------------------------------------------------------------
# 2c') Pure mode_switch layout — NO REAPER, NO SWELL. The Design-View mode-switch
#      geometry (D5): header rect + N modes -> N equal segment rects (exact tiling),
#      and point -> segment hit-test. Split out so the switch's layout math is
#      unit-tested outside the DAW; the bank_panel header strip that draws it and
#      routes clicks to view::applyMode is DAW-verified. Mirror of bank_grid.
# ---------------------------------------------------------------------------
add_library(mode_switch STATIC src/mode_switch.cpp)
target_include_directories(mode_switch PUBLIC src)

# ---------------------------------------------------------------------------
# 2d) Pure view_mode_model library — NO REAPER, NO SWELL. The Design View heart
#     (Phase D1): mode registry + GUID-keyed membership index + folder-tree-aware
#     visibility derivation + parking/restore planner + JSON round-trip. Mirror of
#     bank_model; the folder tree is an INPUT supplied by the D2 shell.
# ---------------------------------------------------------------------------
add_library(view_mode_model STATIC src/view_mode_model.cpp)
target_include_directories(view_mode_model PUBLIC src)

# ---------------------------------------------------------------------------
# 2d) Pure view_tree library — NO REAPER, NO SWELL. The one testable-outside-DAW
#     piece of the D2 view shell: turning REAPER's linear I_FOLDERDEPTH stream into
#     the parent<->child FolderTree the model consumes. The REAPER reads stay in
#     view.cpp; this fiddly folder-depth walk is unit-tested here (mirrors
#     capture_paths splitting the path math out of the capture shell).
# ---------------------------------------------------------------------------
add_library(view_tree STATIC src/view_tree.cpp)
target_include_directories(view_tree PUBLIC src)
target_link_libraries(view_tree PUBLIC view_mode_model)

# ---------------------------------------------------------------------------
# 2e) Pure insert_plan library — NO REAPER, NO SWELL. The InsertMedia `mode`
#     bitmask arithmetic behind the `insert` shell (M6). Split out so the
#     load-bearing bit computation (no silent stretch, opt-in conform) is
#     unit-tested outside the DAW; the InsertMedia call itself is DAW-verified.
# ---------------------------------------------------------------------------
add_library(insert_plan STATIC src/insert_plan.cpp)
target_include_directories(insert_plan PUBLIC src)

# ---------------------------------------------------------------------------
# 2f) Pure render_settings library — NO REAPER, NO SWELL. The M7 capture-family
#     logic: source-mode + wet/dry -> RENDER_SETTINGS bit value, P_RAZOREDITS
#     string -> time ranges + union bound, and the capture-action taxonomy table.
#     Split out so the fiddly bit-mapping / razor-parsing is unit-tested outside
#     the DAW; the render-driving + selection reads stay in capture.cpp / main.cpp.
#     Depends on bank_model for the pure SourceMode enum.
# ---------------------------------------------------------------------------
add_library(render_settings STATIC src/render_settings.cpp)
target_include_directories(render_settings PUBLIC src)
target_link_libraries(render_settings PUBLIC bank_model)

# ---------------------------------------------------------------------------
# 3) Standalone tests for the pure modules (run without launching REAPER).
# ---------------------------------------------------------------------------
enable_testing()
add_executable(bank_model_tests tests/test_bank_model.cpp)
target_link_libraries(bank_model_tests PRIVATE bank_model)
add_test(NAME bank_model_tests COMMAND bank_model_tests)

add_executable(peaks_tests tests/test_peaks.cpp)
target_link_libraries(peaks_tests PRIVATE peaks)
add_test(NAME peaks_tests COMMAND peaks_tests)

add_executable(capture_paths_tests tests/test_capture_paths.cpp)
target_link_libraries(capture_paths_tests PRIVATE capture_paths)
add_test(NAME capture_paths_tests COMMAND capture_paths_tests)

add_executable(bank_grid_tests tests/test_bank_grid.cpp)
target_link_libraries(bank_grid_tests PRIVATE bank_grid)
add_test(NAME bank_grid_tests COMMAND bank_grid_tests)

add_executable(mode_switch_tests tests/test_mode_switch.cpp)
target_link_libraries(mode_switch_tests PRIVATE mode_switch)
add_test(NAME mode_switch_tests COMMAND mode_switch_tests)

add_executable(view_mode_model_tests tests/test_view_mode_model.cpp)
target_link_libraries(view_mode_model_tests PRIVATE view_mode_model)
add_test(NAME view_mode_model_tests COMMAND view_mode_model_tests)

add_executable(view_tree_tests tests/test_view_tree.cpp)
target_link_libraries(view_tree_tests PRIVATE view_tree)
add_test(NAME view_tree_tests COMMAND view_tree_tests)

add_executable(insert_plan_tests tests/test_insert_plan.cpp)
target_link_libraries(insert_plan_tests PRIVATE insert_plan)
add_test(NAME insert_plan_tests COMMAND insert_plan_tests)

add_executable(render_settings_tests tests/test_render_settings.cpp)
target_link_libraries(render_settings_tests PRIVATE render_settings)
add_test(NAME render_settings_tests COMMAND render_settings_tests)

# ---------------------------------------------------------------------------
# 4) The REAPER extension — a loadable module (dlopen'd by REAPER, not linked).
# ---------------------------------------------------------------------------
# LICE sources the bank_panel draws with: lice.cpp (LICE_SysBitmap, FillRect,
# Clear, Blit) + lice_line.cpp (Line, DrawRect). lice_line.cpp's bezier helpers
# call LICE_FillCircle from lice_arc.cpp, so that TU is required to link even
# though the panel draws no arcs. LICE routes GDI through native Win32 or, on
# mac/linux, the host SWELL (SWELL_PROVIDED_BY_APP).
set(LICE_SRC
    ${WDL_INC}/lice/lice.cpp
    ${WDL_INC}/lice/lice_line.cpp
    ${WDL_INC}/lice/lice_arc.cpp
)

add_library(reaper_reasampler MODULE
    src/main.cpp
    src/capture.cpp
    src/persist.cpp
    src/bank_panel.cpp
    src/mode_switch.cpp
    src/insert.cpp
    src/insert_plan.cpp
    ${LICE_SRC}
    src/view_mode_model.cpp
    src/view_tree.cpp
    src/view.cpp
    src/track_guid.cpp
    src/actions.cpp
)
target_link_libraries(reaper_reasampler PRIVATE bank_model capture_paths peaks bank_grid mode_switch view_mode_model insert_plan render_settings)
target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC})
set_target_properties(reaper_reasampler PROPERTIES PREFIX "" OUTPUT_NAME "reaper_reasampler")

if(WIN32)
    # Native Win32. REAPER provides nothing extra to link. The bank_panel dialog
    # template (M5) is compiled from src/resource.rc by the platform RC compiler.
    target_sources(reaper_reasampler PRIVATE src/resource.rc)

elseif(APPLE)
    # macOS: use REAPER's OWN SWELL at runtime via the modstub.
    # Do NOT build full SWELL. SWELL_PROVIDED_BY_APP routes calls to the host.
    target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub.mm)
    target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
    target_link_libraries(reaper_reasampler PRIVATE "-framework AppKit")
    set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".dylib")
    # bank_panel dialog (M5): SWELL can't read a Win32 .rc directly. Run resgen
    # once to turn src/resource.rc into a C++ source, then add it here:
    #   php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
    # target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h)  # generated

else()
    # Linux: REAPER's libSwell.so is used at runtime via the generic modstub.
    # With SWELL_PROVIDED_BY_APP you can drop pkg-config / -lX11 entirely.
    target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub-generic.cpp)
    target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
    set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".so")
    # bank_panel dialog (M5): reuse the macOS resgen output (see README /
    # CLAUDE.md §SWELL dialog resources), then add the generated source:
    #   php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
    # target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h)  # generated
endif()
