cmake_minimum_required(VERSION 3.16)

project(stable-diffusion.cpp-rest
    VERSION 1.0.0
    DESCRIPTION "REST API server for stable-diffusion.cpp"
    LANGUAGES CXX
)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Set build type if not specified
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

# Add cmake modules path
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# Include dependencies
include(FindDependencies)

# Option for CUDA support
option(SD_CUDA_SUPPORT "Enable CUDA support in stable-diffusion.cpp" ON)

# Option for building Web UI
option(BUILD_WEBUI "Build the web UI and bundle it with the server" ON)

# Option for PAM authentication support
option(ENABLE_PAM_AUTH "Enable PAM (Pluggable Authentication Modules) support" ON)

# Find CUDA if support is enabled
if(SD_CUDA_SUPPORT)
    find_package(CUDAToolkit REQUIRED)
    message(STATUS "CUDA Toolkit found: ${CUDAToolkit_VERSION}")
endif()

# ExternalProject for stable-diffusion.cpp
include(ExternalProject)

# Set up external project for stable-diffusion.cpp
ExternalProject_Add(stable-diffusion.cpp
    GIT_REPOSITORY https://github.com/leejet/stable-diffusion.cpp.git
    GIT_TAG master-347-6103d86
    SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.cpp-src"
    BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.cpp-build"
    CMAKE_ARGS
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.cpp-install
        -DSD_CUDA=${SD_CUDA_SUPPORT}
    BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}
    INSTALL_COMMAND ${CMAKE_COMMAND} --install . --config ${CMAKE_BUILD_TYPE}
    LOG_DOWNLOAD ON
    LOG_CONFIGURE ON
    LOG_BUILD ON
    LOG_INSTALL ON
)

# Get the include directories and libraries from the external project
ExternalProject_Get_Property(stable-diffusion.cpp SOURCE_DIR BINARY_DIR)

# Set include directories for the external project
set(SD_CPP_INCLUDE_DIRS
    ${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.cpp-install/include
    ${SOURCE_DIR}
    ${SOURCE_DIR}/ggml/include
)

# Set library directories
set(SD_CPP_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.cpp-install/lib)

# Build Web UI if enabled
if(BUILD_WEBUI)
    # Check if Node.js and npm are available
    find_program(NPM_EXECUTABLE npm)

    if(NPM_EXECUTABLE)
        message(STATUS "npm found: ${NPM_EXECUTABLE}")
        message(STATUS "Web UI will be built and bundled")

        # Set the output directory for the web UI
        set(WEBUI_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/webui)
        set(WEBUI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/webui)

        # Get git commit hash for versioning
        find_package(Git QUIET)
        if(GIT_FOUND)
            execute_process(
                COMMAND ${GIT_EXECUTABLE} rev-parse --short=8 HEAD
                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                OUTPUT_VARIABLE GIT_COMMIT_HASH
                OUTPUT_STRIP_TRAILING_WHITESPACE
                ERROR_QUIET
            )
            if(NOT GIT_COMMIT_HASH)
                set(GIT_COMMIT_HASH "unknown")
            endif()
        else()
            set(GIT_COMMIT_HASH "unknown")
        endif()
        message(STATUS "Git commit hash for UI versioning: ${GIT_COMMIT_HASH}")

        # Get build timestamp
        string(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%dT%H:%M:%SZ" UTC)

        # Create custom target for building the web UI
        add_custom_target(webui-build
            COMMAND ${CMAKE_COMMAND} -E echo "Building Web UI..."
            # Clean build/webui directory before building
            COMMAND ${CMAKE_COMMAND} -E remove_directory ${WEBUI_OUTPUT_DIR}
            COMMAND ${CMAKE_COMMAND} -E make_directory ${WEBUI_OUTPUT_DIR}
            # Generate version file
            COMMAND ${CMAKE_COMMAND} -E echo "{\"version\":\"${GIT_COMMIT_HASH}\",\"buildTime\":\"${BUILD_TIMESTAMP}\"}" > ${WEBUI_SOURCE_DIR}/public/version.json
            COMMAND ${NPM_EXECUTABLE} install
            COMMAND ${NPM_EXECUTABLE} run build
            COMMAND ${CMAKE_COMMAND} -E copy_directory ${WEBUI_SOURCE_DIR}/out ${WEBUI_OUTPUT_DIR}
            WORKING_DIRECTORY ${WEBUI_SOURCE_DIR}
            COMMENT "Building Web UI with npm (version: ${GIT_COMMIT_HASH})"
            VERBATIM
        )

        # Set a variable that can be used by the server
        set(WEBUI_BUILT ON)
        set(WEBUI_PATH ${WEBUI_OUTPUT_DIR} CACHE PATH "Path to built web UI files")

        message(STATUS "Web UI output directory: ${WEBUI_OUTPUT_DIR}")
    else()
        message(WARNING "npm not found. Web UI will not be built. Install Node.js to enable Web UI building.")
        set(BUILD_WEBUI OFF)
    endif()
else()
    message(STATUS "Web UI building is disabled")
endif()

# Add subdirectories
add_subdirectory(src)

# Create an interface target for stable-diffusion.cpp
add_library(sd-cpp INTERFACE)
add_dependencies(sd-cpp stable-diffusion.cpp)
target_include_directories(sd-cpp INTERFACE ${SD_CPP_INCLUDE_DIRS})
target_link_directories(sd-cpp INTERFACE ${SD_CPP_LIB_DIR})

# Set up libraries list based on CUDA support
set(SD_LIBS
    stable-diffusion
    ggml
    ggml-base
    ggml-cpu
)

if(SD_CUDA_SUPPORT)
    list(APPEND SD_LIBS ggml-cuda)
    list(APPEND SD_LIBS CUDA::cudart CUDA::cublas CUDA::cuda_driver)
endif()

target_link_libraries(sd-cpp INTERFACE ${SD_LIBS})

# Print configuration summary
message(STATUS "Configuration Summary:")
message(STATUS "  Build Type: ${CMAKE_BUILD_TYPE}")
message(STATUS "  C++ Standard: ${CMAKE_CXX_STANDARD}")
message(STATUS "  CUDA Support: ${SD_CUDA_SUPPORT}")
message(STATUS "  Build Web UI: ${BUILD_WEBUI}")
message(STATUS "  PAM Authentication: ${ENABLE_PAM_AUTH}")
if(BUILD_WEBUI AND WEBUI_BUILT)
    message(STATUS "  Web UI Path: ${WEBUI_PATH}")
endif()