cmake_minimum_required(VERSION 3.20)
project(cf_workspace_store_provider LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(GNUInstallDirs)

function(_cf_workspace_store_first_existing_path out_var)
  foreach(_candidate IN LISTS ARGN)
    if (NOT _candidate STREQUAL "" AND EXISTS "${_candidate}")
      set(${out_var} "${_candidate}" PARENT_SCOPE)
      return()
    endif()
  endforeach()
  set(${out_var} "" PARENT_SCOPE)
endfunction()

function(_cf_workspace_store_find_repo_native_duckdb_root out_var)
  set(_search_roots
    "${CMAKE_SOURCE_DIR}"
    "${PROJECT_SOURCE_DIR}"
    "${CMAKE_CURRENT_SOURCE_DIR}"
  )

  foreach(_search_root IN LISTS _search_roots)
    if (_search_root STREQUAL "" OR NOT IS_DIRECTORY "${_search_root}")
      continue()
    endif()

    set(_cursor "${_search_root}")
    while (TRUE)
      set(_candidate "${_cursor}/.native_deps/duckdb")
      if (EXISTS "${_candidate}")
        set(${out_var} "${_candidate}" PARENT_SCOPE)
        return()
      endif()

      get_filename_component(_parent "${_cursor}" DIRECTORY)
      if (_parent STREQUAL "${_cursor}")
        break()
      endif()
      set(_cursor "${_parent}")
    endwhile()
  endforeach()

  set(${out_var} "" PARENT_SCOPE)
endfunction()

function(_cf_workspace_store_find_cache_native_duckdb_root out_var)
  set(_version_candidates "")
  if (NOT "$ENV{DUCKDB_VERSION}" STREQUAL "")
    list(APPEND _version_candidates "$ENV{DUCKDB_VERSION}")
  endif()
  list(APPEND _version_candidates "1.4.2")
  list(REMOVE_DUPLICATES _version_candidates)

  set(_triplet_candidates
    "x64-windows-static"
    "x64-windows"
  )

  set(_cache_roots
    "$ENV{CF_NATIVE_CACHE_DIR}/duckdb"
    "$ENV{USERPROFILE}/.cogniflow/cache/native/duckdb"
    "$ENV{HOME}/.cogniflow/cache/native/duckdb"
  )

  foreach(_cache_root IN LISTS _cache_roots)
    if (_cache_root STREQUAL "" OR NOT IS_DIRECTORY "${_cache_root}")
      continue()
    endif()

    foreach(_version IN LISTS _version_candidates)
      foreach(_triplet IN LISTS _triplet_candidates)
        set(_candidate "${_cache_root}/${_version}/${_triplet}")
        if (EXISTS "${_candidate}")
          set(${out_var} "${_candidate}" PARENT_SCOPE)
          return()
        endif()
      endforeach()
    endforeach()

    file(GLOB _cache_version_dirs LIST_DIRECTORIES true "${_cache_root}/*")
    list(SORT _cache_version_dirs COMPARE NATURAL ORDER DESCENDING)
    foreach(_version_dir IN LISTS _cache_version_dirs)
      if (NOT IS_DIRECTORY "${_version_dir}")
        continue()
      endif()
      foreach(_triplet IN LISTS _triplet_candidates)
        set(_candidate "${_version_dir}/${_triplet}")
        if (EXISTS "${_candidate}")
          set(${out_var} "${_candidate}" PARENT_SCOPE)
          return()
        endif()
      endforeach()
    endforeach()
  endforeach()

  set(${out_var} "" PARENT_SCOPE)
endfunction()

get_filename_component(_CF_REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../../.." ABSOLUTE)
include("${_CF_REPO_ROOT}/tools/cmake/cf_contracts_include.cmake")
set(CF_SDK_INCLUDE "${CF_CONTRACTS_INCLUDE}")

set(_native_duckdb_root "$ENV{CF_WORKSPACE_STORE_DUCKDB_ROOT}")
if (_native_duckdb_root STREQUAL "")
  _cf_workspace_store_find_cache_native_duckdb_root(_native_duckdb_root)
endif()
if (_native_duckdb_root STREQUAL "")
  _cf_workspace_store_find_repo_native_duckdb_root(_native_duckdb_root)
endif()
if (_native_duckdb_root STREQUAL "")
  set(_native_duckdb_root "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../.native_deps/duckdb")
endif()
file(TO_CMAKE_PATH "${_native_duckdb_root}" _native_duckdb_root)

set(_native_duckdb_include "${_native_duckdb_root}/include")
set(_native_duckdb_include_flat "${_native_duckdb_root}")
set(_native_duckdb_src "${_native_duckdb_root}/src")
set(_native_duckdb_lib_win "${_native_duckdb_root}/lib/duckdb.lib")
set(_native_duckdb_lib_mingw "${_native_duckdb_root}/lib/libduckdb.a")
set(_native_duckdb_lib_flat "${_native_duckdb_root}/duckdb.lib")
set(_native_duckdb_src_cpp "${_native_duckdb_src}/duckdb.cpp")
set(_native_duckdb_runtime_dll "${_native_duckdb_root}/bin/duckdb.dll")

set(_duckdb_include_candidates
  "$ENV{CF_WORKSPACE_STORE_DUCKDB_INCLUDE}"
  "$ENV{CF_DATAHIVE_CPP_DUCKDB_INCLUDE}"
  "${_native_duckdb_src}"
  "${_native_duckdb_include}"
  "${_native_duckdb_include_flat}"
)
_cf_workspace_store_first_existing_path(
  CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR
  ${_duckdb_include_candidates}
)
if (NOT CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR STREQUAL "")
  file(TO_CMAKE_PATH "${CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR}" CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR)
endif()

set(_duckdb_library_candidates
  "$ENV{CF_WORKSPACE_STORE_DUCKDB_LIBRARY}"
  "$ENV{CF_WORKSPACE_STORE_DUCKDB_LIB}"
  "$ENV{CF_DATAHIVE_CPP_DUCKDB_LIB}"
  "${_native_duckdb_lib_win}"
  "${_native_duckdb_lib_mingw}"
  "${_native_duckdb_lib_flat}"
)
_cf_workspace_store_first_existing_path(
  CF_WORKSPACE_STORE_DUCKDB_LIBRARY
  ${_duckdb_library_candidates}
)
if (NOT CF_WORKSPACE_STORE_DUCKDB_LIBRARY STREQUAL "")
  file(TO_CMAKE_PATH "${CF_WORKSPACE_STORE_DUCKDB_LIBRARY}" CF_WORKSPACE_STORE_DUCKDB_LIBRARY)
endif()

if (NOT _native_duckdb_runtime_dll STREQUAL "")
  file(TO_CMAKE_PATH "${_native_duckdb_runtime_dll}" _native_duckdb_runtime_dll)
endif()

if (CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR STREQUAL "" OR NOT EXISTS "${CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR}/duckdb.h")
  message(FATAL_ERROR "DuckDB headers not found. Resolved root='${_native_duckdb_root}', include='${CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR}'.")
endif()

if (CF_WORKSPACE_STORE_DUCKDB_LIBRARY STREQUAL "" OR NOT EXISTS "${CF_WORKSPACE_STORE_DUCKDB_LIBRARY}")
  message(FATAL_ERROR "DuckDB library not found. Resolved root='${_native_duckdb_root}', library='${CF_WORKSPACE_STORE_DUCKDB_LIBRARY}'.")
endif()

add_library(cf_workspace_store_provider SHARED
  workspace_store_contract_provider.cpp
)

target_compile_definitions(cf_workspace_store_provider PRIVATE CF_STEP_ABI_EXPORTS)
target_include_directories(cf_workspace_store_provider PRIVATE
  ${CF_SDK_INCLUDE}
  ${CF_WORKSPACE_STORE_DUCKDB_INCLUDE_DIR}
)
target_link_libraries(cf_workspace_store_provider PRIVATE
  ${CF_WORKSPACE_STORE_DUCKDB_LIBRARY}
)
set_target_properties(cf_workspace_store_provider PROPERTIES
  PREFIX ""
)

install(TARGETS cf_workspace_store_provider
  RUNTIME DESTINATION cf_workspace_store/native/bin
  LIBRARY DESTINATION cf_workspace_store/native/lib
)

if (WIN32 AND EXISTS "${_native_duckdb_runtime_dll}")
  install(FILES ${_native_duckdb_runtime_dll} DESTINATION cf_workspace_store/native/bin)
endif()
