cmake_minimum_required(VERSION 3.20)
project(pydaasiot LANGUAGES CXX)

# Evita warning FetchContent su timestamp estrazione (CMake >= 3.24)
if (POLICY CMP0135)
  cmake_policy(SET CMP0135 NEW)
endif()

# --- Python / pybind11 ------------------------------------------------------
find_package(pybind11 REQUIRED)  # config-package
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Allinea la CRT alla runtime di Python su MSVC
if (MSVC)
  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()

# --- LibDaaS: fetch precompilato cross-platform -----------------------------
include(FetchContent)

# Parametri sovrascrivibili (-D)
set(DAAS_VERSION "0.20.01" CACHE STRING "LibDaaS version (as in v-0.20.01)")
set(DAAS_FILETAG "0201"     CACHE STRING "Short tag used in filenames (e.g., 0201)")
set(DAAS_MD5 ""             CACHE STRING "MD5 of the LibDaaS archive")

# Piattaforma e archivio
if (WIN32)
  set(_DAAS_PLATFORM_DIR "windows/msvc")
  set(_DAAS_ARCHIVE      "libdaas-${DAAS_FILETAG}-windows-msvc.tar.gz")
elseif (UNIX)
  set(_DAAS_PLATFORM_DIR "linux/gcc")
  set(_DAAS_ARCHIVE      "libdaas-${DAAS_FILETAG}-linux-gcc.tar.gz")
else()
  message(FATAL_ERROR "Unsupported platform")
endif()

set(_DAAS_BASE_URL "https://daasiot.sebyone.it/releases/libdaas/v-${DAAS_VERSION}/${_DAAS_PLATFORM_DIR}")
set(_DAAS_URL      "${_DAAS_BASE_URL}/${_DAAS_ARCHIVE}")

# Se MD5 non passato da CLI/CI, tenta download del .md5 ufficiale
if (DAAS_MD5 STREQUAL "")
  set(_md5_file "${CMAKE_BINARY_DIR}/libdaas.md5")
  file(DOWNLOAD "${_DAAS_URL}.md5" "${_md5_file}" SHOW_PROGRESS STATUS _st)
  list(GET _st 0 _code)
  if(_code EQUAL 0)
    file(READ "${_md5_file}" _md5_content)
    string(STRIP "${_md5_content}" _md5_content)
    string(REGEX MATCH "^[0-9a-fA-F]+" DAAS_MD5 "${_md5_content}")
    if(DAAS_MD5 STREQUAL "")
      message(FATAL_ERROR "[LibDaaS] Unable to parse MD5 from ${_DAAS_URL}.md5")
    else()
      message(STATUS "[LibDaaS] MD5 fetched: ${DAAS_MD5}")
    endif()
  else()
    message(FATAL_ERROR "[LibDaaS] Failed to download MD5 from ${_DAAS_URL}.md5. Pass -DDAAS_MD5=...")
  endif()
endif()

message(STATUS "[LibDaaS] Version : ${DAAS_VERSION}")
message(STATUS "[LibDaaS] Filetag : ${DAAS_FILETAG}")
message(STATUS "[LibDaaS] URL     : ${_DAAS_URL}")

# Scarica/estrai il pacchetto (timestamp di estrazione per robustezza)
FetchContent_Declare(daaslib_pkg
  URL      "${_DAAS_URL}"
  URL_HASH "MD5=${DAAS_MD5}"
  DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_MakeAvailable(daaslib_pkg)

# Percorsi interni attesi: include/ e lib/...
set(_DAAS_INC "${daaslib_pkg_SOURCE_DIR}/include")
if (WIN32)
  set(_LIB_A "${daaslib_pkg_SOURCE_DIR}/lib/libdaas.lib")
  set(_LIB_B "${daaslib_pkg_SOURCE_DIR}/lib/daas.lib")
else()
  set(_LIB_A "${daaslib_pkg_SOURCE_DIR}/lib/libdaas.a")
  set(_LIB_B "${daaslib_pkg_SOURCE_DIR}/lib/libdaas.so")
endif()

if (EXISTS "${_LIB_A}")
  set(_DAAS_LIB "${_LIB_A}")
elseif (EXISTS "${_LIB_B}")
  set(_DAAS_LIB "${_LIB_B}")
else()
  message(FATAL_ERROR "[LibDaaS] Library not found in ${daaslib_pkg_SOURCE_DIR}/lib")
endif()

if (NOT EXISTS "${_DAAS_INC}")
  message(FATAL_ERROR "[LibDaaS] include/ not found in ${daaslib_pkg_SOURCE_DIR}")
endif()

# Target IMPORTED che espone include + libreria (no copia in repo)
add_library(daaslib::prebuilt UNKNOWN IMPORTED GLOBAL)
set_target_properties(daaslib::prebuilt PROPERTIES
  IMPORTED_LOCATION             "${_DAAS_LIB}"
  INTERFACE_INCLUDE_DIRECTORIES "${_DAAS_INC}"
)

# --- Modulo Python (pybind11) ----------------------------------------------
# NB: il nome del target deve coincidere col nome nel codice C++: PYBIND11_MODULE(_core, m)
pybind11_add_module(_core
  src/cpp/pydaasiot.cpp
  src/cpp/daaswrapper.cpp
  src/cpp/net_utils.cpp
)

# Include locali del wrapper + terze parti
target_include_directories(_core
  PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/third-parties"
)

# (Consigliato) visibilità simboli più pulita
set_target_properties(_core PROPERTIES
  CXX_VISIBILITY_PRESET hidden
  VISIBILITY_INLINES_HIDDEN ON
)

# Link a libdaas + dipendenze OS-specific
if (WIN32)
  target_link_libraries(_core PRIVATE
    daaslib::prebuilt
    Ws2_32
    Bthprops
  )

  # Se il pacchetto includesse una DLL, copiala accanto al .pyd (solo in output)
  set(_PKG_DLL "${daaslib_pkg_SOURCE_DIR}/bin/libdaas.dll")
  if(EXISTS "${_PKG_DLL}")
    add_custom_command(TARGET _core POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different
              "${_PKG_DLL}" "$<TARGET_FILE_DIR:_core>/libdaas.dll"
      COMMENT "Copying libdaas.dll next to the built .pyd"
      VERBATIM
    )
  endif()

  if(MSVC)
    target_link_options(_core PRIVATE "/VERBOSE:LIB")
  endif()
elseif (UNIX)
  # Dipendenze tipiche Linux
  find_package(Threads REQUIRED)

  # BlueZ OBBLIGATORIO: libdaas usa hci_get_route & co.
  find_library(BLUEZ_LIB bluetooth)
  if (NOT BLUEZ_LIB)
    message(FATAL_ERROR
      "BlueZ (libbluetooth) non trovata. "
      "Installa il pacchetto di sviluppo (es. 'bluez-libs-devel' su manylinux, "
      "'libbluetooth-dev' su Debian/Ubuntu) prima di costruire pydaasiot."
    )
  endif()

  target_link_libraries(_core PRIVATE
    daaslib::prebuilt
    Threads::Threads
    ${BLUEZ_LIB}
  )

  # RPATH per caricare .so accanto al modulo
  set_target_properties(_core PROPERTIES
    INSTALL_RPATH "\$ORIGIN"
    BUILD_WITH_INSTALL_RPATH ON
  )
endif()

# --- (Opzionale) Doxygen ----------------------------------------------------
find_package(Doxygen QUIET)
if(DOXYGEN_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile")
  set(DOXYFILE_IN  "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile")
  set(DOXYFILE_OUT "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
  configure_file("${DOXYFILE_IN}" "${DOXYFILE_OUT}" @ONLY)
  add_custom_target(doc_doxygen
    COMMAND "${DOXYGEN_EXECUTABLE}" "${DOXYFILE_OUT}"
    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
    COMMENT "Generating API documentation with Doxygen"
    VERBATIM
  )
else()
  message(STATUS "Doxygen not found or Doxyfile missing; documentation target not generated.")
endif()

# --- Install modulo nel package Python --------------------------------------
install(TARGETS _core DESTINATION pydaasiot)
