
find_package(PkgConfig REQUIRED)
pkg_check_modules(WAVSEN_AVFORMAT    REQUIRED IMPORTED_TARGET libavformat>=58)
pkg_check_modules(WAVSEN_AVCODEC     REQUIRED IMPORTED_TARGET libavcodec>=58)
pkg_check_modules(WAVSEN_AVUTIL      REQUIRED IMPORTED_TARGET libavutil>=56)
pkg_check_modules(WAVSEN_SWSCALE     REQUIRED IMPORTED_TARGET libswscale>=5)
pkg_check_modules(WAVSEN_SWRESAMPLE           IMPORTED_TARGET libswresample>=3)
# Optional: VAAPI hardware decode. Headers + symbols come from libavutil
# itself; libva pkg-config is presence-checked so the build also succeeds
# against an FFmpeg compiled without --enable-vaapi.
pkg_check_modules(WAVSEN_LIBVA                IMPORTED_TARGET libva libva-drm)

set(WAVSEN_AUDIO_BACKEND "pulse" CACHE STRING
    "Audio backend for wavsen::audio (pulse|pipewire)")
set_property(CACHE WAVSEN_AUDIO_BACKEND PROPERTY STRINGS pulse pipewire)

if(WAVSEN_AUDIO_BACKEND STREQUAL "pulse")
    pkg_check_modules(WAVSEN_LIBPULSE REQUIRED libpulse>=14.0)
elseif(WAVSEN_AUDIO_BACKEND STREQUAL "pipewire")
    pkg_check_modules(WAVSEN_LIBPIPEWIRE REQUIRED libpipewire-0.3)
else()
    message(FATAL_ERROR
        "WAVSEN_AUDIO_BACKEND='${WAVSEN_AUDIO_BACKEND}' is not one of: pulse pipewire")
endif()

if(NOT TARGET vvk::vvk)
    message(FATAL_ERROR
        "wavsen requires the host project to provide vvk::vvk")
endif()

# ---------------------------------------------------------------------------
# wavsen::ffi::* — C++20 module wrappers around external APIs. Each is
# its own STATIC library so external consumers can pick & link them.
# ---------------------------------------------------------------------------
add_subdirectory(src/ffi/ffmpeg)
if(WAVSEN_AUDIO_BACKEND STREQUAL "pulse")
    add_subdirectory(src/ffi/pulse)
else()
    add_subdirectory(src/ffi/pipewire)
endif()

add_library(wavsen_decode STATIC)
add_library(wavsen::decode ALIAS wavsen_decode)

target_compile_features(wavsen_decode PUBLIC cxx_std_20)

target_sources(wavsen_decode
    PUBLIC FILE_SET CXX_MODULES FILES
        src/decode/decoder.cppm
)
target_sources(wavsen_decode PRIVATE
    src/decode/decoder.cpp
)

target_link_libraries(wavsen_decode
    PUBLIC
        rstd::rstd
        wavsen::ffi::ffmpeg
    PRIVATE
        rstd.cppstd
)
set_target_properties(wavsen_decode PROPERTIES CXX_SCAN_FOR_MODULES ON)


find_program(GLSLANG_VALIDATOR
    NAMES glslangValidator
    DOC   "GLSL → SPIR-V compiler used to bake wavsen::video shaders")
if(NOT GLSLANG_VALIDATOR)
    message(FATAL_ERROR
        "wavsen: glslangValidator not found in PATH — required to build "
        "wavsen::video's NV12→RGBA shader. Install Vulkan SDK or the "
        "`glslang` distro package, or set GLSLANG_VALIDATOR.")
endif()

set(_wavsen_shader_src ${CMAKE_CURRENT_SOURCE_DIR}/shaders/nv12_to_rgba.comp)
set(_wavsen_shader_hdr ${CMAKE_CURRENT_BINARY_DIR}/generated/nv12_to_rgba.spv.h)
add_custom_command(
    OUTPUT  ${_wavsen_shader_hdr}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/generated
    COMMAND ${GLSLANG_VALIDATOR} -V --vn nv12_to_rgba_spv
            -o ${_wavsen_shader_hdr} ${_wavsen_shader_src}
    DEPENDS ${_wavsen_shader_src}
    COMMENT "wavsen: compiling NV12→RGBA compute shader"
    VERBATIM
)

add_library(wavsen_video STATIC
    ${_wavsen_shader_hdr}
)
add_library(wavsen::video ALIAS wavsen_video)

target_compile_features(wavsen_video PUBLIC cxx_std_20)
target_include_directories(wavsen_video
    PRIVATE
        ${CMAKE_CURRENT_BINARY_DIR}/generated
)
target_sources(wavsen_video
    PUBLIC FILE_SET CXX_MODULES FILES
        src/video/wavsen_video.cppm
        src/video/vk_device.cppm
        src/video/video_decoder.cppm
        src/video/yuv_to_rgba.cppm
        src/video/presenter.cppm
)
target_sources(wavsen_video PRIVATE
    src/video/vk_device.cpp
    src/video/video_decoder.cpp
    src/video/yuv_to_rgba.cpp
)
target_link_libraries(wavsen_video
    PUBLIC
        rstd::rstd
        wavsen::ffi::ffmpeg
        vvk::vvk
    PRIVATE
        rstd.log
)
set_property(TARGET wavsen_video PROPERTY POSITION_INDEPENDENT_CODE ON)
set_target_properties(wavsen_video PROPERTIES CXX_SCAN_FOR_MODULES ON)

if(NOT WAVSEN_SWRESAMPLE_FOUND)
    message(FATAL_ERROR
        "wavsen::audio requires libswresample (pkg-config). Install "
        "ffmpeg dev headers including libswresample.")
endif()

add_library(wavsen_audio STATIC)
add_library(wavsen::audio ALIAS wavsen_audio)

target_compile_features(wavsen_audio PUBLIC cxx_std_20)

target_sources(wavsen_audio
    PUBLIC FILE_SET CXX_MODULES FILES
        src/audio/byte_stream.cppm
        src/audio/audio_device.cppm
        src/audio/sound_manager.cppm
        src/audio/stream_decoder.cppm
        src/audio/av_player.cppm
        src/audio/audio_capture.cppm
        # aggregator must come last (depends on the partitions above)
        src/audio/audio.cppm
)
target_sources(wavsen_audio
    PRIVATE FILE_SET wavsen_audio_internal_modules TYPE CXX_MODULES FILES
        src/audio/audio_gain.cppm
        src/audio/audio_capture_dsp.cppm
)
target_sources(wavsen_audio PRIVATE
    src/audio/stream_decoder.cpp
    src/audio/sound_manager.cpp
    src/audio/av_player.cpp
)

if(WAVSEN_AUDIO_BACKEND STREQUAL "pulse")
    target_sources(wavsen_audio PRIVATE
        src/audio/audio_device_pulse.cpp
        src/audio/audio_capture_pulse.cpp
    )
    set(_wavsen_audio_backend_target wavsen::ffi::pulse)
else()
    target_sources(wavsen_audio PRIVATE
        src/audio/audio_device_pipewire.cpp
        src/audio/audio_capture_pipewire.cpp
    )
    set(_wavsen_audio_backend_target wavsen::ffi::pipewire)
endif()

target_link_libraries(wavsen_audio
    PUBLIC
        rstd::rstd
        rstd.cppstd
        wavsen::ffi::ffmpeg
    PRIVATE
        rstd.log
        ${_wavsen_audio_backend_target}
)
set_target_properties(wavsen_audio PROPERTIES CXX_SCAN_FOR_MODULES ON)

option(WAVSEN_BUILD_TESTS "Build wavsen test executables" OFF)
if(WAVSEN_BUILD_TESTS)
    enable_testing()
    add_executable(wavsen_audio_capture_dsp_tests
        tests/audio_capture_dsp_tests.cpp
    )
    target_compile_features(wavsen_audio_capture_dsp_tests PRIVATE cxx_std_20)
    target_sources(wavsen_audio_capture_dsp_tests
        PRIVATE FILE_SET CXX_MODULES FILES
            src/audio/audio_capture_dsp.cppm
    )
    target_link_libraries(wavsen_audio_capture_dsp_tests PRIVATE rstd::rstd)
    add_test(NAME wavsen_audio_capture_dsp_tests
             COMMAND wavsen_audio_capture_dsp_tests)

    add_executable(wavsen_audio_gain_tests
        tests/audio_gain_tests.cpp
    )
    target_compile_features(wavsen_audio_gain_tests PRIVATE cxx_std_20)
    target_sources(wavsen_audio_gain_tests
        PRIVATE FILE_SET CXX_MODULES FILES
            src/audio/audio_gain.cppm
    )
    target_link_libraries(wavsen_audio_gain_tests PRIVATE rstd::rstd)
    add_test(NAME wavsen_audio_gain_tests
             COMMAND wavsen_audio_gain_tests)
endif()
