# SPDX-FileCopyrightText: (C) 2024 - 2025 Deskflow Developers
# SPDX-FileCopyrightText: (C) 2024 Symless Ltd
# SPDX-License-Identifier: MIT

macro(configure_libs)

  set(libs)
  if(UNIX)
    configure_unix_libs()
  elseif(WIN32)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2")
    list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi version)
    add_definitions(
      /DWIN32
      /D_WINDOWS
      /D_CRT_SECURE_NO_WARNINGS
      /D_XKEYCHECK_H
    )
  endif()

  find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Widgets Network)
  if(UNIX AND NOT APPLE)
      find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus Xml)
  endif()

  # Define the location of Qt deployment tool
  if(WIN32)
    if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND VCPKG_QT)
      set(DEPLOY_TOOL windeployqt.debug.bat)
    else()
      set(DEPLOY_TOOL windeployqt)
    endif()
  elseif(APPLE)
      set(DEPLOY_TOOL macdeployqt)
  endif()

  if (WIN32 OR APPLE)
    find_program(DEPLOYQT ${DEPLOY_TOOL})
    if(DEPLOYQT STREQUAL "DEPLOYQT-NOTFOUND")
      message(FATAL_ERROR "Unable to locate the Qt Deploy Tool: \"${DEPLOY_TOOL}\"")
    endif()
    unset(DEPLOY_TOOL)
  endif()

  set(CMAKE_AUTOMOC ON)
  set(CMAKE_AUTOUIC ON)
  set(CMAKE_AUTORCC ON)

  message(STATUS "Qt version: ${Qt6_VERSION}")

  # Check if <format> header is available
  check_cxx_source_compiles("
    #include <format>
    int main() {
        char buffer[100];
        std::format_to_n(buffer, 100, \"test {}\", 42);
        return 0;
    }
    " HAVE_FORMAT)

  if(HAVE_FORMAT)
    add_definitions(-DHAVE_FORMAT)
  endif()

  option(ENABLE_COVERAGE "Enable test coverage" OFF)
  if(ENABLE_COVERAGE)
    message(STATUS "Enabling code coverage")
    include(cmake/CodeCoverage.cmake)
    append_coverage_compiler_flags()
    set(test_exclude subprojects/* build/* src/unittests/*)
    set(test_src ${PROJECT_SOURCE_DIR}/src)

    # Apparently solves the bug in gcov where it returns negative counts and confuses gcovr.
    # > Got negative hit value in gcov line 'branch  2 taken -1' caused by a bug in gcov tool
    # Bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68080
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-update=atomic")

    setup_target_for_coverage_gcovr_xml(
      NAME coverage-legacytests
      EXECUTABLE legacytests
      BASE_DIRECTORY ${test_src}
      EXCLUDE ${test_exclude}
    )
  endif()

endmacro()

#
# Unix (Mac, Linux, BSD, etc)
#
macro(configure_unix_libs)

  if(NOT APPLE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
  endif()

  # For config.h, detect the libraries, functions, etc.
  include(CheckIncludeFiles)
  include(CheckLibraryExists)
  include(CheckFunctionExists)
  include(CheckTypeSize)
  include(CheckIncludeFileCXX)
  include(CheckSymbolExists)
  include(CheckCSourceCompiles)
  include(CheckCXXSourceCompiles)

  check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
  if (NOT HAVE_SYS_SOCKET_H)
    message(FATAL_ERROR "Missing header: sys/socket.h")
  endif()


  check_include_files(unistd.h HAVE_UNISTD_H)
  if (NOT HAVE_UNISTD_H)
    message(FATAL_ERROR "Missing unistd.h")
  endif()

  check_function_exists(sigwait HAVE_POSIX_SIGWAIT)
  if (NOT HAVE_POSIX_SIGWAIT)
    message(FATAL_ERROR "Missing posix sigwait")
  endif()

  # pthread is used on both Linux and Mac
  check_library_exists("pthread" pthread_create "" HAVE_PTHREAD)
  if(HAVE_PTHREAD)
    list(APPEND libs pthread)
  else()
    message(FATAL_ERROR "Missing library: pthread")
  endif()

  if(APPLE)
    set(CMAKE_CXX_FLAGS "--sysroot ${CMAKE_OSX_SYSROOT} ${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1")
    find_library(lib_ScreenSaver ScreenSaver)
    find_library(lib_IOKit IOKit)
    find_library(lib_ApplicationServices ApplicationServices)
    find_library(lib_Foundation Foundation)
    find_library(lib_Carbon Carbon)
    find_library(lib_UserNotifications UserNotifications)
    list(APPEND libs
      ${lib_ScreenSaver} ${lib_IOKit} ${lib_ApplicationServices}
      ${lib_Foundation} ${lib_Carbon} ${lib_UserNotifications}
    )

    add_definitions(-DWINAPI_CARBON=1)
  else()

    if (BUILD_X11_SUPPORT)
      configure_xorg_libs()
    endif()

    include(FindPkgConfig)
    find_package(PkgConfig)
    if(PKG_CONFIG_FOUND)
      pkg_check_modules(LIBXKBCOMMON REQUIRED xkbcommon)
      pkg_check_modules(GLIB2 REQUIRED glib-2.0)
      find_library(LIBM m)
      include_directories(${LIBXKBCOMMON_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}
                          ${LIBM_INCLUDE_DIRS})
      
      message(STATUS "xkbcommon version: ${LIBXKBCOMMON_VERSION}")
    else()
      message(WARNING "pkg-config not found, skipping wayland libraries")
    endif()
  endif()

  add_definitions(-DSYSAPI_UNIX=1)

endmacro()

#
# X.org/X11 for Linux, BSD, etc
#
macro(configure_xorg_libs)

  # Set include dir for BSD-derived systems
  set(CMAKE_REQUIRED_INCLUDES "/usr/local/include")

  set(XKBlib "X11/Xlib.h;X11/XKBlib.h")
  set(CMAKE_EXTRA_INCLUDE_FILES "${XKBlib};X11/extensions/Xrandr.h")
  check_type_size("XRRNotifyEvent" X11_EXTENSIONS_XRANDR_H)
  set(HAVE_X11_EXTENSIONS_XRANDR_H "${X11_EXTENSIONS_XRANDR_H}")
  set(CMAKE_EXTRA_INCLUDE_FILES)

  check_include_files("${XKBlib};X11/extensions/dpms.h"
                      HAVE_X11_EXTENSIONS_DPMS_H)
  check_include_files("X11/extensions/Xinerama.h"
                      HAVE_X11_EXTENSIONS_XINERAMA_H)
  check_include_files("X11/extensions/XKB.h" HAVE_XKB_EXTENSION)
  check_include_files("X11/extensions/XTest.h" HAVE_X11_EXTENSIONS_XTEST_H)
  check_include_files("${XKBlib}" HAVE_X11_XKBLIB_H)
  check_include_files("X11/extensions/XInput2.h" HAVE_XI2)

  if(NOT HAVE_X11_XKBLIB_H)
    message(FATAL_ERROR "Missing header: " ${XKBlib})
  endif()

  # Set library path and -L flag for BSD-derived systems.
  # On our FreeBSD CI, `link_directories` is also needed for some reason.
  set(CMAKE_LIBRARY_PATH "/usr/local/lib")
  set(CMAKE_REQUIRED_FLAGS "-L${CMAKE_LIBRARY_PATH}")
  link_directories(${CMAKE_LIBRARY_PATH})

  check_library_exists("SM;ICE" IceConnectionNumber "" HAVE_ICE)
  check_library_exists("Xext;X11" DPMSQueryExtension "" HAVE_Xext)
  check_library_exists("Xtst;Xext;X11" XTestQueryExtension "" HAVE_Xtst)
  check_library_exists("Xinerama" XineramaQueryExtension "" HAVE_Xinerama)
  check_library_exists("Xi" XISelectEvents "" HAVE_Xi)
  check_library_exists("Xrandr" XRRQueryExtension "" HAVE_Xrandr)

  if(HAVE_ICE)

    # Assume we have SM if we have ICE.
    set(HAVE_SM 1)
    list(APPEND libs SM ICE)

  endif()

  if(!X11_xkbfile_FOUND)
    message(FATAL_ERROR "Missing library: xkbfile")
  endif()

  if(HAVE_Xtst)

    # Xtxt depends on X11.
    set(HAVE_X11)
    list(
      APPEND
      libs
      Xtst
      X11
      xkbfile)

  else()

    message(FATAL_ERROR "Missing library: Xtst")

  endif()

  if(HAVE_Xext)
    list(APPEND libs Xext)
  endif()

  if(HAVE_Xinerama)
    list(APPEND libs Xinerama)
  else(HAVE_Xinerama)
    if(HAVE_X11_EXTENSIONS_XINERAMA_H)
      set(HAVE_X11_EXTENSIONS_XINERAMA_H 0)
      message(WARNING "Old Xinerama implementation detected, disabled")
    endif()
  endif()

  if(HAVE_Xrandr)
    list(APPEND libs Xrandr)
  endif()

  # this was outside of the linux scope, not sure why, moving it back inside.
  if(HAVE_Xi)
    list(APPEND libs Xi)
  endif()

  add_definitions(-DWINAPI_XWINDOWS=1)

endmacro()
