# SPDX-FileCopyrightText: 2026 Ian Monroe <imonroe@kde.org>
#
# SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL

find_package(Qt6 REQUIRED COMPONENTS Core Qml Test)

# FLAC is a test-only dependency: libFLAC generates the deterministic
# fixtures used by the gapless tests. It is never checked or linked when
# tests are disabled.
pkg_check_modules(FLAC REQUIRED IMPORTED_TARGET flac)

include(ECMMarkNonGuiExecutable)

option(DRAGON_CI_PIPEWIRE "Start a headless PipeWire daemon for audio tests" OFF)
option(DRAGON_CI_NO_AUDIO "Disable tests that require a real audio device (for headless Windows CI)" OFF)

function(dragon_add_test name)
    cmake_parse_arguments(ARG "" "" "LIBRARIES;ENVIRONMENT" ${ARGN})
    add_executable(${name} ${name}.cpp)
    # let's you use see the output in the terminal on Windows:
    ecm_mark_nongui_executable(${name})
    target_include_directories(${name} PRIVATE ${PROJECT_SOURCE_DIR}/src)
    target_link_libraries(${name} PRIVATE DragonMediaBackend Qt6::Test ${ARG_LIBRARIES})
    target_compile_definitions(${name} PRIVATE
        DRAGON_SDL_TESTS_FIXTURES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/fixtures"
    )
    add_test(NAME ${name} COMMAND ${name})
    set(_qt_plugin_path "${PROJECT_BINARY_DIR}/bin")
    if(DEFINED ENV{QT_PLUGIN_PATH} AND NOT "$ENV{QT_PLUGIN_PATH}" STREQUAL "")
        if(WIN32)
            string(APPEND _qt_plugin_path ";$ENV{QT_PLUGIN_PATH}")
        else()
            string(APPEND _qt_plugin_path ":$ENV{QT_PLUGIN_PATH}")
        endif()
    endif()
    # needed for Windows:
    string(REPLACE ";" "\\;" _qt_plugin_path "${_qt_plugin_path}")
    set_property(TEST ${name} APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
        ${ARG_ENVIRONMENT}
    )
endfunction()

set(_dragon_audio_tests
    test_player_basics
    test_player_playback_sdl
    test_player_playback_pulseaudio
    test_player_playback_pipewire
    test_player_signals
    test_player_setsource
    test_player_prefinish
    test_player_fft
    test_e2e
    test_e2e_sdl
    test_e2e_pulseaudio
    test_e2e_pipewire
    test_network_playback
    test_audiooutput_sdl
    test_audiooutput_pulseaudio
    test_audiooutput_pipewire
    test_player_streamname_sdl
    test_player_streamname_pulseaudio
    test_player_streamname_pipewire
)

if(DRAGON_CI_PIPEWIRE AND NOT WIN32)
    add_test(NAME pipewire_setup
        COMMAND bash ${CMAKE_SOURCE_DIR}/ci/start-pipewire.sh
                ${CMAKE_SOURCE_DIR}/ci/pipewire-daemon.conf
    )
    set_tests_properties(pipewire_setup PROPERTIES
        FIXTURES_SETUP "dragon_pipewire"
    )

    add_test(NAME pipewire_cleanup
        COMMAND bash -c "killall pipewire wireplumber 2>/dev/null || true"
    )
    set_tests_properties(pipewire_cleanup PROPERTIES
        FIXTURES_CLEANUP "dragon_pipewire"
    )
endif()

# Unit tests
dragon_add_test(test_generator LIBRARIES Qt6::Core)
dragon_add_test(test_completion LIBRARIES Qt6::Core QCoro6::Core)
dragon_add_test(test_fftprocessor LIBRARIES kissfft::kissfft spsc_queue)
dragon_add_test(test_decoder LIBRARIES Qt6::Network PkgConfig::FFmpeg)
dragon_add_test(test_decoder_fixtures LIBRARIES Qt6::Network PkgConfig::FFmpeg)
dragon_add_test(test_pipe LIBRARIES DragonMediaBackend spsc_queue)
dragon_add_test(test_drainstate LIBRARIES Qt6::Core)
dragon_add_test(test_positionestimator LIBRARIES Qt6::Core)

# Stream tests
dragon_add_test(test_radiostream LIBRARIES Qt6::Network)
dragon_add_test(test_kiostream LIBRARIES Qt6::Network KF6::KIOCore)

# Player tests
set(_player_libs Qt6::Network SDL3::SDL3 PkgConfig::FFmpeg spsc_queue kissfft::kissfft)
dragon_add_test(test_dragonduration LIBRARIES ${_player_libs})
dragon_add_test(test_dragonduration_qml LIBRARIES ${_player_libs} Qt6::Qml)

# QML module import test: loads org.kde.dragonmediabackend via an import
# path the way the standalone qml6 runtime does (no context properties).
dragon_add_test(test_qml_module LIBRARIES ${_player_libs} Qt6::Qml)
target_compile_definitions(test_qml_module PRIVATE
    DRAGON_QML_IMPORT_PATH="${PROJECT_BINARY_DIR}/bin"
)
dragon_add_test(test_sink_null        LIBRARIES ${_player_libs})
dragon_add_test(test_player_basics    LIBRARIES ${_player_libs})
# Playback state tests are sensitive to audio-sink timing differences;
# build one executable and run it once per backend via env var.
dragon_add_test(test_player_playback  LIBRARIES ${_player_libs})
set_tests_properties(test_player_playback PROPERTIES DISABLED TRUE)
dragon_add_test(test_player_signals   LIBRARIES ${_player_libs})
dragon_add_test(test_player_setsource LIBRARIES ${_player_libs})
dragon_add_test(test_player_prefinish LIBRARIES ${_player_libs})
dragon_add_test(test_player_fft       LIBRARIES ${_player_libs})

# Integration tests
dragon_add_test(test_e2e              LIBRARIES Qt6::Network PkgConfig::FFmpeg)
set_tests_properties(test_e2e PROPERTIES DISABLED TRUE)

set(_qt_plugin_path "${PROJECT_BINARY_DIR}/bin")
if(DEFINED ENV{QT_PLUGIN_PATH} AND NOT "$ENV{QT_PLUGIN_PATH}" STREQUAL "")
    if(WIN32)
        string(APPEND _qt_plugin_path ";$ENV{QT_PLUGIN_PATH}")
    else()
        string(APPEND _qt_plugin_path ":$ENV{QT_PLUGIN_PATH}")
    endif()
endif()

# needed for Windows:
string(REPLACE ";" "\\;" _qt_plugin_path "${_qt_plugin_path}")

add_test(NAME test_e2e_sdl COMMAND test_e2e)
set_property(TEST test_e2e_sdl APPEND PROPERTY ENVIRONMENT
    "QT_QPA_PLATFORM=offscreen"
    "DRAGON_AUDIO_SINK=dragonsdlaudiosink"
    "QT_PLUGIN_PATH=${_qt_plugin_path}"
)
if(PULSEAUDIO_FOUND)
    add_test(NAME test_e2e_pulseaudio COMMAND test_e2e)
    set_property(TEST test_e2e_pulseaudio APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpulseaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()
if(PIPEWIRE_FOUND)
    add_test(NAME test_e2e_pipewire COMMAND test_e2e)
    set_property(TEST test_e2e_pipewire APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpipewireaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()

# Playback state tests (one executable, run once per backend via env var)
add_test(NAME test_player_playback_sdl COMMAND test_player_playback)
set_property(TEST test_player_playback_sdl APPEND PROPERTY ENVIRONMENT
    "QT_QPA_PLATFORM=offscreen"
    "DRAGON_AUDIO_SINK=dragonsdlaudiosink"
    "QT_PLUGIN_PATH=${_qt_plugin_path}"
)
if(PULSEAUDIO_FOUND)
    add_test(NAME test_player_playback_pulseaudio COMMAND test_player_playback)
    set_property(TEST test_player_playback_pulseaudio APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpulseaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()
if(PIPEWIRE_FOUND)
    add_test(NAME test_player_playback_pipewire COMMAND test_player_playback)
    set_property(TEST test_player_playback_pipewire APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpipewireaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()

dragon_add_test(test_network_playback LIBRARIES ${_player_libs})

# SDL gapless tests uses SDL disk driver for PCM capture verification
dragon_add_test(test_e2e_sdl_gapless LIBRARIES ${_player_libs} PkgConfig::FLAC)
set_property(TEST test_e2e_sdl_gapless APPEND PROPERTY ENVIRONMENT
    "DRAGON_AUDIO_SINK=dragonsdlaudiosink"
)

# PipeWire gapless tests requires PipeWire + WirePlumber with dragon-test-sink (monitor ports)
if(PIPEWIRE_FOUND)
    dragon_add_test(test_e2e_pipewire_gapless LIBRARIES ${_player_libs} PkgConfig::FLAC PkgConfig::PIPEWIRE)
    if(DRAGON_CI_PIPEWIRE AND NOT WIN32)
        set_tests_properties(test_e2e_pipewire_gapless PROPERTIES
            FIXTURES_REQUIRED "dragon_pipewire"
        )
    endif()
endif()

# PulseAudio gapless tests Pulse client output routed to dragon-test-sink,
# captured via PipeWire monitor ports (requires PulseAudio on PipeWire)
if(PIPEWIRE_FOUND AND PULSEAUDIO_FOUND)
    dragon_add_test(test_e2e_pulseaudio_gapless LIBRARIES ${_player_libs} PkgConfig::FLAC PkgConfig::PIPEWIRE)
    if(DRAGON_CI_PIPEWIRE AND NOT WIN32)
        set_tests_properties(test_e2e_pulseaudio_gapless PROPERTIES
            FIXTURES_REQUIRED "dragon_pipewire"
        )
    endif()
endif()

# Audio output tests (one executable, run once per backend via env var)
dragon_add_test(test_audiooutput LIBRARIES SDL3::SDL3 spsc_queue Qt6::Gui)
set_tests_properties(test_audiooutput PROPERTIES DISABLED TRUE)

add_test(NAME test_audiooutput_sdl COMMAND test_audiooutput)
set_property(TEST test_audiooutput_sdl APPEND PROPERTY ENVIRONMENT
    "QT_QPA_PLATFORM=offscreen"
    "DRAGON_AUDIO_SINK=dragonsdlaudiosink"
    "QT_PLUGIN_PATH=${_qt_plugin_path}"
)
if(PULSEAUDIO_FOUND)
    add_test(NAME test_audiooutput_pulseaudio COMMAND test_audiooutput)
    set_property(TEST test_audiooutput_pulseaudio APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpulseaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()
if(PIPEWIRE_FOUND)
    add_test(NAME test_audiooutput_pipewire COMMAND test_audiooutput)
    set_property(TEST test_audiooutput_pipewire APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpipewireaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()

# Stream-name player semantics (one executable, run once per backend via env var)
dragon_add_test(test_player_streamname LIBRARIES ${_player_libs} Qt6::Gui)
set_tests_properties(test_player_streamname PROPERTIES DISABLED TRUE)

add_test(NAME test_player_streamname_sdl COMMAND test_player_streamname)
set_property(TEST test_player_streamname_sdl APPEND PROPERTY ENVIRONMENT
    "QT_QPA_PLATFORM=offscreen"
    "DRAGON_AUDIO_SINK=dragonsdlaudiosink"
    "QT_PLUGIN_PATH=${_qt_plugin_path}"
)
if(PULSEAUDIO_FOUND)
    add_test(NAME test_player_streamname_pulseaudio COMMAND test_player_streamname)
    set_property(TEST test_player_streamname_pulseaudio APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpulseaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()
if(PIPEWIRE_FOUND)
    add_test(NAME test_player_streamname_pipewire COMMAND test_player_streamname)
    set_property(TEST test_player_streamname_pipewire APPEND PROPERTY ENVIRONMENT
        "QT_QPA_PLATFORM=offscreen"
        "DRAGON_AUDIO_SINK=dragonpipewireaudiosink"
        "QT_PLUGIN_PATH=${_qt_plugin_path}"
    )
endif()

if(DRAGON_CI_PIPEWIRE AND NOT WIN32)
    foreach(_test ${_dragon_audio_tests} test_e2e_pipewire_gapless test_e2e_pulseaudio_gapless)
        if(TEST ${_test})
            set_tests_properties(${_test} PROPERTIES
                FIXTURES_REQUIRED "dragon_pipewire"
            )
        endif()
    endforeach()
endif()

if(DRAGON_CI_NO_AUDIO)
    set(_no_audio_tests ${_dragon_audio_tests} test_e2e_sdl_gapless test_e2e_pipewire_gapless test_e2e_pulseaudio_gapless test_audiooutput test_player_playback)
    foreach(_test ${_no_audio_tests})
        if(TEST ${_test})
            set_tests_properties(${_test} PROPERTIES DISABLED TRUE)
        endif()
    endforeach()
endif()
