# To link extensions into DuckDB and auto-load them on startup, we generated an
# include file and a loader function based on the `DUCKDB_EXTENSION_NAMES`
# parameter.

# generated_extension_headers.hpp we first write into a 'candidate' file and
# then use `configure_file` again the advantage of this is that we don't change
# modification time if nothing changed

add_library(dummy_static_extension_loader STATIC
            loader/dummy_static_extension_loader.cpp)

install(
  TARGETS dummy_static_extension_loader
  EXPORT "${DUCKDB_EXPORT_SET}"
  LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
  ARCHIVE DESTINATION "${INSTALL_LIB_DIR}")

configure_file(
  generated_extension_headers.hpp.in
  "${PROJECT_BINARY_DIR}/codegen/include/generated_extension_headers.hpp.cand")

get_statically_linked_extensions("${DUCKDB_EXTENSION_NAMES}"
                                 STATICALLY_LINKED_EXTENSIONS)
foreach(EXT_NAME IN LISTS STATICALLY_LINKED_EXTENSIONS)
  string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE)
  if(${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK})
    get_property(
      EXT_KIND
      TARGET ${EXT_NAME}_extension
      PROPERTY DUCKDB_EXTENSION_KIND)
    if(NOT "${EXT_KIND}" STREQUAL "CAPI")
      set(DUCKDB_EXTENSION_HEADER "${EXT_NAME}_extension.hpp")
      file(
        APPEND
        "${PROJECT_BINARY_DIR}/codegen/include/generated_extension_headers.hpp.cand"
        "#include \"${DUCKDB_EXTENSION_HEADER}\"\n")
    endif()
  endif()
endforeach()

configure_file(
  "${PROJECT_BINARY_DIR}/codegen/include/generated_extension_headers.hpp.cand"
  "${PROJECT_BINARY_DIR}/codegen/include/generated_extension_headers.hpp")

# generated_extension_loader.hpp
set(EXT_LOADER_NAME_LIST "")
set(EXT_LOADER_BODY "")
set(EXT_CAPI_DECLARATIONS "")
foreach(EXT_NAME IN LISTS STATICALLY_LINKED_EXTENSIONS)
  string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE)
  if(${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK})

    # Assumes lowercase input!
    string(REPLACE "_" ";" EXT_NAME_SPLIT ${EXT_NAME})
    set(EXT_NAME_CAMELCASE "")
    foreach(EXT_NAME_PART IN LISTS EXT_NAME_SPLIT)
      string(SUBSTRING ${EXT_NAME_PART} 0 1 FIRST_LETTER)
      string(SUBSTRING ${EXT_NAME_PART} 1 -1 REMAINDER)
      string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
      set(EXT_NAME_CAMELCASE "${EXT_NAME_CAMELCASE}${FIRST_LETTER}${REMAINDER}")
    endforeach()

    get_property(
      EXT_KIND
      TARGET ${EXT_NAME}_extension
      PROPERTY DUCKDB_EXTENSION_KIND)
    set(EXT_LOADER_NAME_LIST "${EXT_LOADER_NAME_LIST},\n\t\"${EXT_NAME}\"")
    if("${EXT_KIND}" STREQUAL "CAPI")
      set(EXT_CAPI_DECLARATIONS
          "${EXT_CAPI_DECLARATIONS}extern \"C\" bool ${EXT_NAME}_init_c_api(duckdb_extension_info, duckdb_extension_access *);\n"
      )
      set(EXT_LOADER_BODY
          "${EXT_LOADER_BODY}\
    if (extension==\"${EXT_NAME}\") {
        db.LoadStaticCAPIExtension(\"${EXT_NAME}\", ${EXT_NAME}_init_c_api);
        return ExtensionLoadResult::LOADED_EXTENSION;
    }
")
    else()
      set(EXT_LOADER_BODY
          "${EXT_LOADER_BODY}\
    if (extension==\"${EXT_NAME}\") {
        db.LoadStaticExtension<${EXT_NAME_CAMELCASE}Extension>();
        return ExtensionLoadResult::LOADED_EXTENSION;
    }
")
    endif()
  endif()
endforeach()

# trim comma
if(NOT ${EXT_LOADER_NAME_LIST} STREQUAL "")
  string(SUBSTRING ${EXT_LOADER_NAME_LIST} 1 -1 EXT_NAME_VECTOR_INITIALIZER)
endif()

# Load test paths for extensions whose SQLLogicTests need to be registered
set(EXT_TEST_PATH_LIST "")
foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES)
  string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE)
  if(${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_LOAD_TESTS})
    set(EXT_TEST_PATH_LIST
        "${EXT_TEST_PATH_LIST},\n\t\"${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_TEST_PATH}\""
    )
  endif()
endforeach()

if(NOT ${EXT_TEST_PATH_LIST} STREQUAL "")
  string(SUBSTRING ${EXT_TEST_PATH_LIST} 1 -1 EXT_TEST_PATH_INITIALIZER)
endif()

set(GENERATED_CPP_FILE
    ${PROJECT_BINARY_DIR}/codegen/src/generated_extension_loader.cpp)
configure_file(generated_extension_loader.cpp.in "${GENERATED_CPP_FILE}")
add_library(duckdb_generated_extension_loader STATIC ${GENERATED_CPP_FILE})

set(ALL_OBJECT_FILES
    ${ALL_OBJECT_FILES} $<TARGET_OBJECTS:duckdb_generated_extension_loader>
    PARENT_SCOPE)

install(
  TARGETS duckdb_generated_extension_loader
  EXPORT "${DUCKDB_EXPORT_SET}"
  LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
  ARCHIVE DESTINATION "${INSTALL_LIB_DIR}")
