set(VCPKG_CHECK_CMAKE_BUILD_TYPE "" CACHE STRING "Build type to be checked")

set(Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN "" CACHE INTERNAL "Last loaded package name")

# Call and trace find_package in distinct scope
function(z_vcpkg_check_cmake_package_trace_find)
    set(CMAKE_FIND_DEBUG_MODE ON)
    set(VCPKG_TRACE_FIND_PACKAGE ON)
    find_package(${ARGN})
endfunction()

# Call and trace find_package, ensure that it called twice
macro(vcpkg_check_cmake_package_find package)
    z_vcpkg_check_cmake_package_trace_find("${package}" ${ARGN})
    message(STATUS "Checking that find_package(${package} ...) can be called again")
    find_package("${package}" ${ARGN} QUIET)
    message(STATUS "Checking that find_package(${package} ...) can be called again - done")
    set(Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN "${package}" CACHE INTERNAL "Last loaded package name")
endmacro()

# Check that library variables match the debug/release build type.
# The variable names might be passed in explicitly or guessed from a prefix.
# If no args are given, the prefix is the name of the last package loaded
# by vcpkg_check_cmake_package_find().
function(vcpkg_check_cmake_package_variables)
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "PREFIX" "")
    if(arg_PREFIX AND arg_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "'PREFIX value' must not be used together with other values.")
    endif()
    if(NOT arg_PREFIX AND NOT arg_UNPARSED_ARGUMENTS)
        if(Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN)
            set(arg_PREFIX "${Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN}")
        else()
            message(FATAL_ERROR "Unable to determine the prefix to be checked.")
        endif()
    endif()

    set(libraries_vars "${arg_UNPARSED_ARGUMENTS}")
    if(libraries_vars STREQUAL "")
        string(REGEX REPLACE "_\$" "" prefix "${arg_PREFIX}")
        if(DEFINED "${prefix}_LIBRARIES")
            set(libraries_vars "${prefix}_LIBRARIES")
        elseif(DEFINED "${package}_LIBRARY")
            set(libraries_vars "${prefix}_LIBRARY")
        endif()
        if(DEFINED "${prefix}_LIBRARY_DIR")
            list(APPEND "libraries_vars" "${${prefix}_LIBRARY_DIR}")
        endif()
        if(DEFINED "${prefix}_LIBRARY_DIRS")
            list(APPEND "libraries_vars" "${${prefix}_LIBRARY_DIRS}")
        endif()
    endif()
    if(libraries_vars STREQUAL "")
        message(FATAL_ERROR "Unable to determine the variables to be checked.")
    endif()

    set(link_keywords debug general optimized)
    foreach(var IN LISTS libraries_vars)
        set(libraries "${${var}}")
        message(STATUS "${var}: ${libraries}")
        set(last_keyword "")
        foreach(item IN LISTS libraries)
            if(item IN_LIST link_keywords)
                set(last_keyword "${item}")
                continue()
            endif()
            string(FIND "${item}" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/" starts_with_release)
            string(FIND "${item}" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib/" starts_with_debug)
            if(starts_with_release EQUAL "0")
                if(last_keyword STREQUAL "optimized")
                    # okay
                elseif(last_keyword STREQUAL "debug")
                    message(SEND_ERROR "Release lib for 'debug' keyword: ${item}")
                elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
                    message(SEND_ERROR "Release lib for 'Debug' build: ${item}")
                endif()
            elseif(starts_with_debug EQUAL "0")
                if(last_keyword STREQUAL "debug")
                    # okay
                elseif(last_keyword STREQUAL "optimized")
                    message(SEND_ERROR "Debug lib for 'optimized' keyword: ${item}")
                elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
                    message(SEND_ERROR "Debug lib for 'Release' build: ${item}")
                endif()
            endif()
            set(last_keyword "")
            continue()
        endforeach()
    endforeach()
endfunction()

# Check that imported target properties match the debug/release build type.
# The target names might be passed in explicitly or guessed from a namespace.
# If no args are given, the namespace is the name of the last package loaded
# by vcpkg_check_cmake_package_find().
function(vcpkg_check_cmake_package_targets)
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "NAMESPACE" "")
    if(arg_NAMESPACE AND arg_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "'NAMESPACE value' must not be used together with other values.")
    endif()
    if(NOT arg_NAMESPACE AND NOT arg_UNPARSED_ARGUMENTS)
        if(Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN)
            set(arg_NAMESPACE "${Z_VCPKG_CHECK_CMAKE_PACKAGE_LAST_SEEN}")
        else()
            message(FATAL_ERROR "Unable to determine the namespace to be checked.")
        endif()
    endif()

    set(targets "${arg_UNPARSED_ARGUMENTS}")
    if(targets STREQUAL "")
        string(REGEX REPLACE "::::\$" "::" namespace "${arg_NAMESPACE}::")
        get_directory_property(targets IMPORTED_TARGETS)
        list(FILTER targets INCLUDE REGEX "^${namespace}")
    endif()
    if(targets STREQUAL "")
        message(FATAL_ERROR "Unable to determine the targets to be checked.")
    endif()

    foreach(target IN LISTS targets)
        if(NOT TARGET "${target}")
            message(FATAL_ERROR "No such target: ${target}")
        endif()
        get_target_property(type "${target}" TYPE)
        message(STATUS "${target}: ${type}")
        if(type MATCHES "LIBRARY" AND NOT type MATCHES "INTERFACE")
            get_target_property(configurations "${target}" IMPORTED_CONFIGURATIONS)
            message(STATUS "  IMPORTED_CONFIGURATIONS: ${configurations}")
            if(configurations)
                string(TOLOWER "${configurations}" configurations)
                if("release" IN_LIST configurations)
                    set(property IMPORTED_IMPLIB_RELEASE)
                    get_target_property(location "${target}" "${property}")
                    if(NOT location)
                        set(property IMPORTED_LOCATION_RELEASE)
                        get_target_property(location "${target}" "${property}")
                    endif()
                    message(STATUS "  ${property}: ${location}")
                    string(FIND "${location}" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" index)
                    if (NOT index EQUAL "0")
                        message(SEND_ERROR "Release lib is in wrong location.")
                    endif()
                elseif(NOT VCPKG_CHECK_CMAKE_BUILD_TYPE OR VCPKG_CHECK_CMAKE_BUILD_TYPE STREQUAL "release")
                    message(SEND_ERROR "Release configuration is missing.")
                endif()
                if("debug" IN_LIST configurations)
                    set(property IMPORTED_IMPLIB_DEBUG)
                    get_target_property(location "${target}" "${property}")
                    if(NOT location)
                        set(property IMPORTED_LOCATION_DEBUG)
                        get_target_property(location "${target}" "${property}")
                    endif()
                    message(STATUS "  ${property}: ${location}")
                    string(FIND "${location}" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" index)
                    if (NOT index EQUAL "0")
                        message(SEND_ERROR "Debug lib is in wrong location.")
                    endif()
                elseif(NOT VCPKG_CHECK_CMAKE_BUILD_TYPE OR VCPKG_CHECK_CMAKE_BUILD_TYPE STREQUAL "debug")
                    message(SEND_ERROR "Debug configuration is missing.")
                endif()
            endif()
        endif()
    endforeach()
endfunction()
