# copyright (c) 2025 Frank Secilia
# SPDX-License-Identifier: MIT

# -----------------------------------------------------------------------------
# Project Files
# -----------------------------------------------------------------------------

list(APPEND dink_library_files
  arity.hpp
  binding.hpp
  binding_dsl.hpp
  cache.hpp
  canonical.hpp
  config.hpp
  container.hpp
  dispatcher.hpp
  invoker.hpp
  lib.hpp
  meta.hpp
  provider.hpp
  resolver.hpp
  scope.hpp
  strategy.hpp
  type_list.hpp
  version.hpp
)

list(APPEND dink_test_files
  arity_test.cpp
  binding_dsl_test.cpp
  cache_test.cpp
  canonical_test.cpp
  config_test.cpp
  container_test.cpp
  dispatcher_test.cpp
  invoker_test.cpp
  meta_test.cpp
  provider_test.cpp
  resolver_test.cpp
  scope_test.cpp
  strategy_test.cpp
  test.hpp
  type_list_test.cpp
  version_test.cpp
)

# -----------------------------------------------------------------------------
# Generated Configuration
# -----------------------------------------------------------------------------

set(dink_config_template_file config.template.hpp)
set(dink_config_gen_filename config.gen.hpp)
set(dink_config_gen_root "${CMAKE_BINARY_DIR}/gen")
set(dink_config_gen_file
  "${dink_config_gen_root}/dink/${dink_config_gen_filename}")
configure_file("${dink_config_template_file}" "${dink_config_gen_file}")

# -----------------------------------------------------------------------------
# Project Definition
# -----------------------------------------------------------------------------

add_library(dink INTERFACE
  ${dink_library_files}
  "${dink_config_template_file}"
  "${dink_config_gen_file}"
)
target_include_directories(dink INTERFACE
  "$<BUILD_INTERFACE:${dink_config_gen_root}>"
  "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
)
set_target_properties(dink
  PROPERTIES
  VERSION ${PROJECT_VERSION}
  SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)

# -----------------------------------------------------------------------------
# Installation
# -----------------------------------------------------------------------------

if (DINK_INSTALL)
    include(GNUInstallDirs)

    # Suppress "Up-to-date" message cmake prints for every installed file.
    set(CMAKE_INSTALL_MESSAGE NEVER)

    # Install library and headers.
    # -----------------------------------------------------------------------------

    # Destination for public headers (e.g., /usr/local/include/dink)
    set(dink_header_install_root "${CMAKE_INSTALL_INCLUDEDIR}/dink")

    # Add headers to install to project property PUBLIC_HEADER.
    set_target_properties(dink PROPERTIES PUBLIC_HEADER "${dink_library_files}")

    # Install library and source header components.
    install(TARGETS dink
      # Associate installed items with an export set named "dink".
      EXPORT dink

      # Install static library, if configured.
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}

      # Install .so, if configured.
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}

      # Install .dll, if configured.
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}

      # Install public headers.
      PUBLIC_HEADER DESTINATION ${dink_header_install_root}
    )

    # Install generated config header.
    install(FILES "${dink_config_gen_file}"
      DESTINATION "${dink_header_install_root}"
    )

    # Install CMake package files.
    # -----------------------------------------------------------------------------
    # This section generates and installs the three files required for
    # find_package(dink) to work correctly.

    include(CMakePackageConfigHelpers)

    # Destination for all CMake config files (e.g., /usr/local/lib/cmake/dink).
    set(dink_cmake_install_root "${CMAKE_INSTALL_LIBDIR}/cmake/dink")

    # Install dink-targets.cmake.
    #
    # This file is included by the main config file. It contains the 'dink::dink'
    # target and its install paths. It is generated directly by the install
    # command.
    install(EXPORT dink
      NAMESPACE dink::
      DESTINATION "${dink_cmake_install_root}"
      FILE "dink-targets.cmake"
    )

    # Generate and install dink-config-version.cmake
    #
    # This file allows find_package() to check the project's version. It is
    # generated by write_basic_package_version_file.
    function(install_dink_config_version)
      set(config_version_file "${PROJECT_BINARY_DIR}/dink-config-version.cmake")

      # Generate the file.
      write_basic_package_version_file(
        "${config_version_file}"
        VERSION "${dink_version}"
        COMPATIBILITY AnyNewerVersion
      )

      # Install the generated file.
      install(
        FILES "${config_version_file}"
        DESTINATION "${dink_cmake_install_root}"
      )
    endfunction()
    install_dink_config_version()

    # Generate and install dink-config.cmake.
    #
    # This is the main "entry point" file for find_package().
    set(dink_cmake_config_template_file "dink-config.template.cmake")
    set(dink_cmake_config_gen_file "${PROJECT_BINARY_DIR}/dink-config.cmake")
    configure_package_config_file(
      "${dink_cmake_config_template_file}"
      "${dink_cmake_config_gen_file}"
      INSTALL_DESTINATION "${dink_cmake_install_root}"
    )
    install(
      FILES "${dink_cmake_config_gen_file}"
      DESTINATION "${dink_cmake_install_root}"
    )
endif()

# -----------------------------------------------------------------------------
# Test Projects
# -----------------------------------------------------------------------------

if (dink_enable_testing)
  add_executable(dink_test ${dink_test_files})
  target_link_libraries(dink_test PUBLIC
    dink
    GTest::gmock_main
    GTest::gtest_main
    GTest::gmock
    GTest::gtest
  )
  dink_configure_test_target_warnings(dink_test)
  dink_enable_running_from_build_tree(dink_test)
  gtest_discover_tests(dink_test)
endif()

add_subdirectory(integration_test)
