if(SFIZZ_USE_SYSTEM_VST3SDK)
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(VST3SDK "vst3sdk" REQUIRED)
    set(VST3SDK_BASEDIR "${VST3SDK_INCLUDE_DIRS}")
else()
    set(VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK")
endif()

#set(AUWRAPPER_BASEDIR "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper")
set(AUWRAPPER_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/sfzt_auwrapper")

# VST plugin specific settings
include(VSTConfig)

configure_file(VstPluginDefs.h.in "${CMAKE_CURRENT_BINARY_DIR}/VstPluginDefs.h")

# Build VST3 SDK
include("cmake/Vst3.cmake")

# Add the ring buffer
set(RINGBUFFER_SOURCES
    "external/ring_buffer/ring_buffer/ring_buffer.h"
    "external/ring_buffer/ring_buffer/ring_buffer.tcc"
    "external/ring_buffer/ring_buffer/ring_buffer.cpp"
)
if(SFIZZ_CMAKE_USE_EMPTY_SOURCE_GROUPS)
    source_group("" FILES ${RINGBUFFER_SOURCES})
endif()

add_library(plugins_ring_buffer STATIC EXCLUDE_FROM_ALL ${RINGBUFFER_SOURCES})
target_include_directories(plugins_ring_buffer PUBLIC "external/ring_buffer")
add_library(plugins::ring-buffer ALIAS plugins_ring_buffer)

# Build the VST shared code
set(VST3_CORE_SOURCES
    SfizzVstProcessor.cpp
    SfizzVstProcessor.h
    SfizzVstController.cpp
    SfizzVstController.h
    SfizzVstEditor.cpp
    SfizzVstEditor.h
    SfizzVstState.cpp
    SfizzVstState.h
    SfizzVstParameters.h
    SfizzVstUpdates.h
    SfizzVstUpdates.hpp
    SfizzVstUpdates.cpp
    SfizzVstIDs.h
    OrderedEventProcessor.h
    OrderedEventProcessor.hpp
    IdleUpdateHandler.h
    X11RunLoop.h
    X11RunLoop.cpp
)
if(SFIZZ_CMAKE_USE_EMPTY_SOURCE_GROUPS)
    source_group("" FILES ${VST3_CORE_SOURCES})
endif()

add_library(plugins_vst3_core STATIC EXCLUDE_FROM_ALL ${VST3_CORE_SOURCES})

target_include_directories(plugins_vst3_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
target_link_libraries(plugins_vst3_core PRIVATE
    sfizz::sfizz
    sfizz::filesystem
    sfizz::import
    sfizz::pugixml
    plugins::common
    plugins::editor
    plugins::ring-buffer
    absl::strings
    absl::optional
    absl::container_common
    vst3sdk
    vst3sdk_vstgui
)
gw_target_warn(plugins_vst3_core PRIVATE
    "-Wno-ignored-qualifiers"
    "-Wno-unused-parameter")
add_library(plugins::vst3_core ALIAS plugins_vst3_core)

# --- VST3 plugin --- #

if(PLUGIN_VST3)
    set(VST3_PLUGIN_PRJ_NAME "plugins_vst3")
    set(VST3_PLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3")

    if(SFIZZ_CMAKE_USE_EMPTY_SOURCE_GROUPS)
        source_group("" FILES VstPluginFactory.cpp)
    endif()

    add_library(${VST3_PLUGIN_PRJ_NAME} MODULE "VstPluginFactory.cpp")

    if(WIN32)
        target_sources(${VST3_PLUGIN_PRJ_NAME} PRIVATE vst3.def)
    endif()

    target_include_directories(${VST3_PLUGIN_PRJ_NAME}
        PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
    target_link_libraries(${VST3_PLUGIN_PRJ_NAME}
        PRIVATE plugins_vst3_core)
    set_target_properties(${VST3_PLUGIN_PRJ_NAME} PROPERTIES
        OUTPUT_NAME "${PROJECT_NAME}"
        PREFIX "")

    plugin_add_vst3sdk(${VST3_PLUGIN_PRJ_NAME})
    plugin_add_vstgui(${VST3_PLUGIN_PRJ_NAME})

    if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
        target_link_libraries(${VST3_PLUGIN_PRJ_NAME} PRIVATE
            "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vst3.version")
    endif()
    sfizz_enable_lto_if_needed(${VST3_PLUGIN_PRJ_NAME})
    if(MINGW)
        set_target_properties(${VST3_PLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static")
    endif()

    # Create the bundle(see "VST 3 Locations / Format")
    execute_process(
        COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    copy_editor_resources(
        ${VST3_PLUGIN_PRJ_NAME}
        "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources"
        "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    if(WIN32)
        set_target_properties(${VST3_PLUGIN_PRJ_NAME} PROPERTIES
            SUFFIX ".vst3"
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win/$<0:>")
        file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/win/Plugin.ico"
            "${CMAKE_CURRENT_SOURCE_DIR}/win/desktop.ini"
            DESTINATION "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}")
    elseif(APPLE)
        set_target_properties(${VST3_PLUGIN_PRJ_NAME} PROPERTIES
            SUFFIX ""
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/MacOS/$<0:>")
        file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo"
            DESTINATION "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents")
        set(SFIZZ_VST3_BUNDLE_EXECUTABLE "${PROJECT_NAME}")
        set(SFIZZ_VST3_BUNDLE_VERSION "${PROJECT_VERSION}")
        configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.vst3.plist"
            "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY)
    else()
        set_target_properties(${VST3_PLUGIN_PRJ_NAME} PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux/$<0:>")
    endif()

    # Copy the license
    if(APPLE)
        # on macOS, files are not permitted at the bundle root, during code signing
        file(COPY "gpl-3.0.txt"
            DESTINATION "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License")
    else()
        file(COPY "gpl-3.0.txt"
            DESTINATION "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}")
    endif()

    # To help debugging the link only
    if(FALSE)
        target_link_options(${VST3_PLUGIN_PRJ_NAME} PRIVATE "-Wl,-no-undefined")
    endif()

    # Installation
    if(NOT MSVC)
        install(DIRECTORY "${PROJECT_BINARY_DIR}/${VST3_PLUGIN_BUNDLE_NAME}"
            DESTINATION "${VST3_PLUGIN_INSTALL_DIR}"
            COMPONENT "vst"
            USE_SOURCE_PERMISSIONS)
        bundle_dylibs(vst
            "${VST3_PLUGIN_INSTALL_DIR}/${VST3_PLUGIN_BUNDLE_NAME}/Contents/MacOS/sfizz"
            COMPONENT "vst")
    endif()
endif()

# --- Audio Unit wrapper --- #

if(PLUGIN_AU AND NOT APPLE)
    message(WARNING "Audio Unit is available only for macOS builds")
elseif(PLUGIN_AU)
    set(AU_PLUGIN_PRJ_NAME "plugins_au")
    set(AU_PLUGIN_BUNDLE_NAME "${PROJECT_NAME}.component")

    add_library(${AU_PLUGIN_PRJ_NAME} MODULE
        "VstPluginFactory.cpp"
        "${AUWRAPPER_BASEDIR}/aucarbonview.mm"
        "${AUWRAPPER_BASEDIR}/aucocoaview.mm"
        "${AUWRAPPER_BASEDIR}/ausdk.mm"
        "${AUWRAPPER_BASEDIR}/auwrapper.mm"
        "${AUWRAPPER_BASEDIR}/NSDataIBStream.mm")
    target_include_directories(${AU_PLUGIN_PRJ_NAME} PRIVATE
        "${CMAKE_CURRENT_BINARY_DIR}"
        "${VST3SDK_BASEDIR}")
    target_link_libraries(${AU_PLUGIN_PRJ_NAME} PRIVATE
        "${APPLE_FOUNDATION_LIBRARY}"
        "${APPLE_COCOA_LIBRARY}"
        "${APPLE_CARBON_LIBRARY}"
        "${APPLE_AUDIOTOOLBOX_LIBRARY}"
        "${APPLE_AUDIOUNIT_LIBRARY}"
        "${APPLE_COREAUDIO_LIBRARY}"
        "${APPLE_COREMIDI_LIBRARY}")

    target_link_libraries(${AU_PLUGIN_PRJ_NAME}
        PRIVATE plugins_vst3_core)
    set_target_properties(${AU_PLUGIN_PRJ_NAME} PROPERTIES
        OUTPUT_NAME "${PROJECT_NAME}"
        PREFIX "")

    plugin_add_vst3sdk(${AU_PLUGIN_PRJ_NAME})
    plugin_add_vstgui(${AU_PLUGIN_PRJ_NAME})

    # Get Core Audio utility classes if missing
    set(CA_UTILITY_BASEDIR
        "${CMAKE_CURRENT_SOURCE_DIR}/external/CoreAudioUtilityClasses")
    if(EXISTS "${CA_UTILITY_BASEDIR}")
        message(STATUS "The CoreAudioUtilityClasses are available locally")
    else()
        message(STATUS "The CoreAudioUtilityClasses are not available locally")

        set(CA_UTILITY_VERSION "1.1")
        set(CA_UTILITY_ARCHIVE "CoreAudioUtilityClasses-${CA_UTILITY_VERSION}.tar.gz")
        set(CA_UTILITY_DOWNLOAD_URL "https://github.com/sfztools/CoreAudioUtilityClasses/releases/download/v${CA_UTILITY_VERSION}/${CA_UTILITY_ARCHIVE}")
        if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/download/${CA_UTILITY_ARCHIVE}")
            message(STATUS "The CoreAudioUtilityClasses archive is available")
        else()
            message(STATUS "The CoreAudioUtilityClasses archive is missing")
            message(STATUS "Downloading: ${CA_UTILITY_DOWNLOAD_URL}")

            file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/download")
            file(DOWNLOAD "${CA_UTILITY_DOWNLOAD_URL}"
                "${CMAKE_CURRENT_SOURCE_DIR}/download/${CA_UTILITY_ARCHIVE}")
        endif()
        message(STATUS "Extracting: ${CA_UTILITY_ARCHIVE}")
        execute_process(COMMAND "${CMAKE_COMMAND}" "-E" "tar" "xvf"
            "${CMAKE_CURRENT_SOURCE_DIR}/download/${CA_UTILITY_ARCHIVE}"
            WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external")
    endif()

    # Add Core Audio utility classes
    target_include_directories(${AU_PLUGIN_PRJ_NAME} PRIVATE
        "${CA_UTILITY_BASEDIR}/CoreAudio"
        "${CA_UTILITY_BASEDIR}/CoreAudio/AudioUnits"
        "${CA_UTILITY_BASEDIR}/CoreAudio/AudioUnits/AUPublic/AUBase"
        "${CA_UTILITY_BASEDIR}/CoreAudio/AudioUnits/AUPublic/Utility"
        "${CA_UTILITY_BASEDIR}/CoreAudio/PublicUtility")

    # Add VST hosting classes
    target_link_libraries(${AU_PLUGIN_PRJ_NAME} PRIVATE vst3sdk_hosting)

    # Add generated source
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
    target_include_directories(${AU_PLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
    string(TIMESTAMP SFIZZ_AU_CLASS_PREFIX_NUMBER "%s" UTC)
    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/aucocoaclassprefix.h"
        "#define SMTG_AU_NAMESPACE SMTGAUCocoa${SFIZZ_AU_CLASS_PREFIX_NUMBER}_")

    sfizz_enable_lto_if_needed(${AU_PLUGIN_PRJ_NAME})

    # Create the bundle
    execute_process(
        COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    copy_editor_resources(
        ${AU_PLUGIN_PRJ_NAME}
        "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources"
        "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    set_target_properties(${AU_PLUGIN_PRJ_NAME} PROPERTIES
        SUFFIX ""
        LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/MacOS/$<0:>")
    file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo"
        DESTINATION "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents")
    set(SFIZZ_AU_BUNDLE_EXECUTABLE "${PROJECT_NAME}")
    set(SFIZZ_AU_BUNDLE_VERSION "${PROJECT_VERSION}")
    set(SFIZZ_AU_BUNDLE_IDENTIFIER "tools.sfz.sfizz.au")
    set(SFIZZ_AU_BUNDLE_TYPE "aumu")
    set(SFIZZ_AU_BUNDLE_SUBTYPE "samp")
    set(SFIZZ_AU_BUNDLE_MANUFACTURER "Sfzt")
    set(SFIZZ_AU_BUNDLE_AUTHOR "SFZTools")
    math(EXPR SFIZZ_AU_DECIMAL_VERSION
        "${PROJECT_VERSION_MAJOR}*256*256 + ${PROJECT_VERSION_MINOR}*256 + ${PROJECT_VERSION_PATCH}")
    execute_process(
        COMMAND "sh" "-c" "echo 'obase=16;${SFIZZ_AU_DECIMAL_VERSION}' | bc"
        OUTPUT_VARIABLE SFIZZ_AU_HEXADECIMAL_VERSION
        OUTPUT_STRIP_TRAILING_WHITESPACE)
    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.au.plist"
        "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY)

    file(COPY "gpl-3.0.txt"
        DESTINATION "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License")

    # Add the resource fork
    if(FALSE)
        execute_process(COMMAND "xcrun" "--find" "Rez"
            OUTPUT_VARIABLE OSX_REZ_COMMAND OUTPUT_STRIP_TRAILING_WHITESPACE)
        file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
        configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/audiounitconfig.h.in"
            "${CMAKE_CURRENT_BINARY_DIR}/include/audiounitconfig.h" @ONLY)
        add_custom_command(TARGET ${AU_PLUGIN_PRJ_NAME} POST_BUILD COMMAND
            "${OSX_REZ_COMMAND}"
            "-d" "SystemSevenOrLater=1"
            "-script" "Roman"
            "-d" "i386_YES"
            "-d" "x86_64_YES"
            "-is" "${CMAKE_OSX_SYSROOT}"
            "-I" "${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers"
            "-I" "/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers"
            "-I" "/System/Library/Frameworks/AudioUnit.framework/Versions/A/Headers/"
            "-I" "${CA_UTILITY_BASEDIR}/CoreAudio/AudioUnits/AUPublic/AUBase"
            "-I" "${CMAKE_CURRENT_BINARY_DIR}/include" # generated audiounitconfig.h
            "-o" "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/Resources/${PROJECT_NAME}.rsrc"
            "-useDF"
            "${AUWRAPPER_BASEDIR}/auresource.r")
    endif()

    # Installation
    if(AU_PLUGIN_INSTALL_DIR)
        install(DIRECTORY "${PROJECT_BINARY_DIR}/${AU_PLUGIN_BUNDLE_NAME}"
            DESTINATION "${AU_PLUGIN_INSTALL_DIR}"
            COMPONENT "au"
            USE_SOURCE_PERMISSIONS)
        bundle_dylibs(au
            "${AU_PLUGIN_INSTALL_DIR}/${AU_PLUGIN_BUNDLE_NAME}/Contents/MacOS/sfizz"
            COMPONENT "au")
    endif()
endif()

# --- VST2 wrapper --- #

if(PLUGIN_VST2)
    set(VST2_PLUGIN_PRJ_NAME "${PROJECT_NAME}_vst2")
    set(VST2_PLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst2")

    set(VST2SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/vstsdk2.4")
    set(VST2WRAPPER_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK/public.sdk/source/vst/vst2wrapper")

    if(NOT EXISTS "${VST2SDK_BASEDIR}/pluginterfaces/vst2.x/aeffect.h")
        message(FATAL_ERROR "VST SDK 2.4 is missing. Make it available in the following folder: ${VST2SDK_BASEDIR}")
    endif()

    add_library(${VST2_PLUGIN_PRJ_NAME} MODULE
        "VstPluginFactory.cpp"
        "Vst2PluginFactory.cpp"
        "Vst2PluginEntry.c"
        "${VST2WRAPPER_BASEDIR}/vst2wrapper.cpp"
        "${VST2WRAPPER_BASEDIR}/../basewrapper/basewrapper.cpp"
        "${VST2SDK_BASEDIR}/public.sdk/source/vst2.x/audioeffect.cpp"
        "${VST2SDK_BASEDIR}/public.sdk/source/vst2.x/audioeffectx.cpp")
    target_include_directories(${VST2_PLUGIN_PRJ_NAME} PRIVATE
        "${CMAKE_CURRENT_BINARY_DIR}"
        "${VST2SDK_BASEDIR}")

    if(NOT WIN32)
        target_compile_definitions(${VST2_PLUGIN_PRJ_NAME} PRIVATE "__cdecl=")
    endif()

    target_link_libraries(${VST2_PLUGIN_PRJ_NAME}
        PRIVATE plugins_vst3_core)
    set_target_properties(${VST2_PLUGIN_PRJ_NAME} PROPERTIES
        OUTPUT_NAME "${PROJECT_NAME}"
        PREFIX "")

    plugin_add_vst3sdk(${VST2_PLUGIN_PRJ_NAME})
    plugin_add_vstgui(${VST2_PLUGIN_PRJ_NAME})

    # Add VST hosting classes
    target_link_libraries(${VST2_PLUGIN_PRJ_NAME} PRIVATE vst3sdk_hosting)

    sfizz_enable_lto_if_needed(${VST2_PLUGIN_PRJ_NAME})

    # Create the bundle
    execute_process(
        COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VST2_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    copy_editor_resources(
        ${VST2_PLUGIN_PRJ_NAME}
        "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources"
        "${PROJECT_BINARY_DIR}/${VST2_PLUGIN_BUNDLE_NAME}/Contents/Resources")
    set_target_properties(${VST2_PLUGIN_PRJ_NAME} PROPERTIES
        LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VST2_PLUGIN_BUNDLE_NAME}/Contents/Binary/$<0:>")

    file(COPY "gpl-3.0.txt"
        DESTINATION "${PROJECT_BINARY_DIR}/${VST2_PLUGIN_BUNDLE_NAME}")

    if(MINGW)
        set_target_properties(${VST2_PLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static")
    endif()

    # Installation
    if(VST2_PLUGIN_INSTALL_DIR)
        install(DIRECTORY "${PROJECT_BINARY_DIR}/${VST2_PLUGIN_BUNDLE_NAME}"
            DESTINATION "${VST2_PLUGIN_INSTALL_DIR}"
            COMPONENT "vst2"
            USE_SOURCE_PERMISSIONS)
        if(APPLE)
            bundle_dylibs(vst2
                "${VST2_PLUGIN_INSTALL_DIR}/${VST2_PLUGIN_BUNDLE_NAME}/Contents/Binary/sfizz.${CMAKE_SHARED_MODULE_SUFFIX}"
                COMPONENT "vst2")
        endif()
    endif()
endif()
