cmake_minimum_required(VERSION 3.16)
project(build_curl)
include(ExternalProject)
include(FetchContent)

if (NOT DEFINED CURL_REPO OR CURL_REPO STREQUAL "")
    set(CURL_REPO https://github.com/curl/curl.git)
endif ()
if (NOT DEFINED OPENSSL_REPO OR OPENSSL_REPO STREQUAL "")
    set(OPENSSL_REPO https://github.com/openssl/openssl.git)
endif ()

set(OPENSSL_SOURCE_DIR ${CMAKE_BINARY_DIR}/deps_curl/openssl-src)
set(OPENSSL_INSTALL_DIR ${CMAKE_BINARY_DIR}/INSTALL)
set(OPENSSL_INCLUDE_DIR ${OPENSSL_INSTALL_DIR}/include)
set(OPENSSL_TAG OpenSSL_1_1_1n)
set(OPENSSL_USE_STATIC_LIBS TRUE)

find_program(PERL_EXECUTABLE perl)
if (NOT PERL_EXECUTABLE)
    message(FATAL_ERROR "Perl not found. Please install Perl to configure OpenSSL.")
endif()

if (MSVC)
    set(OPENSSL_PERL_CONFIGURE_COMMAND ${OPENSSL_SOURCE_DIR}/src/openssl/Configure VC-WIN64A)
    set(OPENSSL_MAKE_COMMAND nmake)
else ()
    set(OPENSSL_PERL_CONFIGURE_COMMAND ${OPENSSL_SOURCE_DIR}/src/OpenSSL/config --static -static -fPIC)
    set(OPENSSL_MAKE_COMMAND make)
endif ()

set(CURL_GIT_TAG curl-8_8_0)

function(InstallOpenSSL)
    ExternalProject_Add(
            OpenSSL
            PREFIX ${OPENSSL_SOURCE_DIR}
            GIT_REPOSITORY ${OPENSSL_REPO}
            GIT_TAG ${OPENSSL_TAG}
            GIT_SHALLOW TRUE
            CONFIGURE_COMMAND ${PERL_EXECUTABLE} ${OPENSSL_PERL_CONFIGURE_COMMAND} --prefix=${OPENSSL_INSTALL_DIR} --openssldir=${OPENSSL_INSTALL_DIR} no-shared no-tests
            BUILD_COMMAND ${OPENSSL_MAKE_COMMAND}
            INSTALL_COMMAND ${OPENSSL_MAKE_COMMAND} install
            INSTALL_DIR ${OPENSSL_INSTALL_DIR}
            USES_TERMINAL_DOWNLOAD TRUE
            USES_TERMINAL_CONFIGURE TRUE
            USES_TERMINAL_BUILD TRUE
            USES_TERMINAL_INSTALL TRUE
        )
endfunction()

function(InstallCurl DEPENDENCY_TARGETS OPENSSL_ROOT_DIR)
    ExternalProject_Add(
        curl
        DEPENDS ${DEPENDENCY_TARGETS}
        GIT_REPOSITORY ${CURL_REPO}
        GIT_TAG ${CURL_GIT_TAG}
        GIT_SHALLOW TRUE
        SOURCE_DIR ${CMAKE_BINARY_DIR}/curl
        BINARY_DIR ${CMAKE_BINARY_DIR}/curl-build
        CMAKE_GENERATOR ${CMAKE_GENERATOR}
        CMAKE_ARGS
            -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${TOOLCHAIN_FILE}
            -DCMAKE_BUILD_TYPE:STRING=Release
            -DCURL_USE_OPENSSL:BOOL=ON
            -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}
            -DOPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR}
            -DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}/INSTALL
            -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/INSTALL
        BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/curl-build --config Release
        INSTALL_COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR}/curl-build --config Release
        USES_TERMINAL_DOWNLOAD TRUE
        USES_TERMINAL_CONFIGURE TRUE
        USES_TERMINAL_BUILD TRUE
        USES_TERMINAL_INSTALL TRUE
    )
endfunction()

if (APPLE)
    ExternalProject_Add(
        curl
        GIT_REPOSITORY ${CURL_REPO}
        GIT_TAG ${CURL_GIT_TAG}
        GIT_SHALLOW TRUE
        SOURCE_DIR ${CMAKE_BINARY_DIR}/curl
        BINARY_DIR ${CMAKE_BINARY_DIR}/curl-build
        CMAKE_GENERATOR ${CMAKE_GENERATOR}
        CMAKE_ARGS
            -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${TOOLCHAIN_FILE}
            -DCMAKE_BUILD_TYPE:STRING=Release
            -DCURL_USE_OPENSSL:BOOL=OFF
            -DBUILD_SHARED_LIBS:BOOL=OFF
            -DBUILD_STATIC_LIBS:BOOL=OFF
            -DBUILD_CURL_EXE:BOOL=OFF
            -DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}/INSTALL
            -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/INSTALL
        BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/curl-build --config Release
        INSTALL_COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR}/curl-build --config Release
        USES_TERMINAL_DOWNLOAD TRUE
        USES_TERMINAL_CONFIGURE TRUE
        USES_TERMINAL_BUILD TRUE
        USES_TERMINAL_INSTALL TRUE
    )
elseif (WIN32)

    set(CURL_DEPDENDENCY_TARGETS "")
    set(OPENSSL_ROOT_DIR ${OPENSSL_INSTALL_DIR})
    list(APPEND CMAKE_PREFIX_PATH ${OPENSSL_INSTALL_DIR})
    
    find_package(OpenSSL QUIET)
    if(NOT OpenSSL_FOUND)
        message("OpenSSL not found. Building OpenSSL from sources...")
        set(CURL_DEPDENDENCY_TARGETS OpenSSL)
        InstallOpenSSL()
    else ()
        set(CURL_DEPDENDENCY_TARGETS OpenSSL::SSL OpenSSL::Crypto)
        message("OpenSSL is already built. Root directory is ${OPENSSL_ROOT_DIR}, include directory is ${OPENSSL_INCLUDE_DIR}")
    endif()

    find_package(CURL QUIET)
    if (NOT CURL_FOUND)
        message("CURL not found. Building CURL from sources...")
        # set(BUILD_SHARED_LIBS OFF) set(BUILD_STATIC_LIBS ON)
        InstallCurl(${CURL_DEPDENDENCY_TARGETS} ${OPENSSL_ROOT_DIR})
    else ()
        message("CURL is already built")
    endif ()
else ()
    InstallOpenSSL()
    ExternalProject_Get_Property(OpenSSL INSTALL_DIR)
    set(OPENSSL_ROOT_DIR ${INSTALL_DIR})
    InstallCurl(OpenSSL ${OPENSSL_ROOT_DIR})
endif ()
