cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0042 NEW)

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")

if(NOT CMAKE_GENERATOR)
    set(CMAKE_GENERATOR "Ninja")
endif()

set(CMAKE_TOOLCHAIN_FILE ../../cpp/deps/vcpkg/scripts/buildsystems/vcpkg.cmake)

if(NOT VCPKG_TARGET_TRIPLET)
    if(WIN32)
        set(VCPKG_TARGET_TRIPLET "x64-windows")
    elseif(APPLE)
        set(VCPKG_TARGET_TRIPLET "x64-osx")
    elseif(DEFINED ENV{ARM64_LINUX})
        set(VCPKG_TARGET_TRIPLET "arm64-linux")
    elseif(DEFINED ENV{RISCV64_LINUX})
        set(VCPKG_TARGET_TRIPLET "riscv64-linux")
    else()
        set(VCPKG_TARGET_TRIPLET "x64-linux")
    endif()
endif()

project (xframes LANGUAGES C CXX)

set (CMAKE_CXX_STANDARD 23)

set(DEPS ${CMAKE_CURRENT_SOURCE_DIR}/../../cpp/deps)
set(APP ${CMAKE_CURRENT_SOURCE_DIR}/../../cpp/app)

find_package(OpenGL REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
find_package(ada CONFIG REQUIRED)
find_package(Stb REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(TIFF REQUIRED)
find_package(CURL REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(qjs CONFIG REQUIRED)
find_package(Lua REQUIRED)
find_package(sol2 CONFIG REQUIRED)

# --- Janet 3-stage bootstrap ---
set(JANET_ROOT "${DEPS}/janet")
set(JANET_SRC_DIR "${JANET_ROOT}/src")
file(GLOB JANET_CORE_SOURCES "${JANET_SRC_DIR}/core/*.c")
file(GLOB JANET_BOOT_SOURCES "${JANET_SRC_DIR}/boot/*.c")
set(JANET_NO_FLAGS JANET_NO_EV JANET_NO_FFI JANET_NO_NET JANET_NO_DYNAMIC_MODULES)

# Stage 1: bootstrap interpreter
add_executable(janet_boot ${JANET_CORE_SOURCES} ${JANET_BOOT_SOURCES})
target_include_directories(janet_boot PRIVATE "${JANET_SRC_DIR}/include" "${JANET_SRC_DIR}/conf")
target_compile_definitions(janet_boot PRIVATE JANET_BOOTSTRAP ${JANET_NO_FLAGS})
if(WIN32)
    target_compile_definitions(janet_boot PRIVATE _CRT_SECURE_NO_WARNINGS)
    target_link_libraries(janet_boot PRIVATE ws2_32)
endif()

# Stage 2: generate core image
set(JANET_IMAGE_FILE "${CMAKE_BINARY_DIR}/janet_core_image.c")
add_custom_command(
    OUTPUT "${JANET_IMAGE_FILE}"
    COMMAND ${CMAKE_COMMAND} -E env "$<TARGET_FILE:janet_boot>" "${JANET_ROOT}" image-only > "${JANET_IMAGE_FILE}"
    DEPENDS janet_boot "${JANET_ROOT}/src/boot/boot.janet"
    COMMENT "Generating Janet core image"
)

# Stage 3: static library (JANET_SINGLE_THREADED: janet_init sets thread-local VM;
# XFrames calls InitJanet on JS thread but Render on render thread)
add_library(janet_core STATIC ${JANET_CORE_SOURCES} "${JANET_IMAGE_FILE}")
target_include_directories(janet_core PUBLIC "${JANET_SRC_DIR}/include" "${JANET_SRC_DIR}/conf")
target_compile_definitions(janet_core PRIVATE ${JANET_NO_FLAGS} JANET_SINGLE_THREADED)
if(WIN32)
    target_compile_definitions(janet_core PRIVATE _CRT_SECURE_NO_WARNINGS)
    target_link_libraries(janet_core PRIVATE ws2_32)
endif()

# Auto-copy core image for WASM builds
add_custom_command(TARGET janet_core POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/../../cpp/app/generated"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different "${JANET_IMAGE_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/../../cpp/app/generated/janet_core_image.c"
    COMMENT "Copying Janet core image to app/generated/ for WASM"
)

include_directories(${CMAKE_JS_INC})

file(GLOB YOGA_SRC CONFIGURE_DEPENDS
        ${DEPS}/yoga/yoga/*.cpp
        ${DEPS}/yoga/yoga/**/*.cpp)

file(GLOB LEPTONICA_SRC "${DEPS}/osm-static-map-generator/cpp/deps/leptonica/src/*.c")

# Generate endianness.h for leptonica (x64 is little-endian)
file(WRITE "${DEPS}/osm-static-map-generator/cpp/deps/leptonica/src/endianness.h" "#define L_LITTLE_ENDIAN\n")
add_compile_definitions(HAVE_LIBJPEG HAVE_LIBTIFF HAVE_LIBPNG NOMINMAX _USE_MATH_DEFINES)

set(OSM_STATIC_MAP_GENERATOR_SRC
        ${DEPS}/osm-static-map-generator/cpp/shared.cpp
        ${DEPS}/osm-static-map-generator/cpp/tiledownloader.cpp
        ${DEPS}/osm-static-map-generator/cpp/mapgenerator.cpp
        ${DEPS}/osm-static-map-generator/cpp/tilecache.cpp
)

add_library(${PROJECT_NAME} SHARED
        ${DEPS}/css-color-parser-cpp/csscolorparser.hpp
        ${DEPS}/css-color-parser-cpp/csscolorparser.cpp

        ${DEPS}/imgui/imgui.cpp
        ${DEPS}/imgui/imgui_draw.cpp
        ${DEPS}/imgui/imgui_widgets.cpp
        ${DEPS}/imgui/imgui_tables.cpp
        ${DEPS}/imgui/misc/cpp/imgui_stdlib.cpp
        ${DEPS}/imgui/backends/imgui_impl_opengl3.cpp
        ${DEPS}/imgui/backends/imgui_impl_glfw.cpp

        ${DEPS}/implot/implot.cpp
        ${DEPS}/implot/implot_items.cpp

        ${YOGA_SRC}

        ${APP}/src/shared.cpp
        ${APP}/src/color_helpers.cpp
        ${APP}/src/yoga_helpers.cpp
        ${APP}/src/imgui_helpers.cpp
        ${APP}/src/disk_tile_cache.cpp

        ${APP}/src/element/layout_node.cpp
        ${APP}/src/element/element.cpp

        ${APP}/src/widget/widget.cpp
        ${APP}/src/widget/styled_widget.cpp

        ${APP}/src/xframes.cpp
        ${APP}/src/imgui_renderer.cpp
        ${APP}/src/implot_renderer.cpp

        ${APP}/src/widget/button.cpp
        ${APP}/src/widget/checkbox.cpp
        ${APP}/src/widget/color_picker.cpp
        ${APP}/src/widget/child.cpp
        ${APP}/src/widget/clipped_multi_line_text_renderer.cpp
        ${APP}/src/widget/collapsing_header.cpp
        ${APP}/src/widget/combo.cpp
        ${APP}/src/widget/group.cpp
        ${APP}/src/widget/image.cpp
        ${APP}/src/widget/input_text.cpp
        ${APP}/src/widget/item_tooltip.cpp
        ${APP}/src/widget/map_view.cpp
        ${APP}/src/widget/multi_slider.cpp
        ${APP}/src/widget/plot_bar.cpp
        ${APP}/src/widget/plot_candlestick.cpp
        ${APP}/src/widget/plot_histogram.cpp
        ${APP}/src/widget/plot_heatmap.cpp
        ${APP}/src/widget/plot_pie_chart.cpp
        ${APP}/src/widget/plot_line.cpp
        ${APP}/src/widget/plot_scatter.cpp
        ${APP}/src/widget/separator.cpp
        ${APP}/src/widget/separator_text.cpp
        ${APP}/src/widget/progress_bar.cpp
        ${APP}/src/widget/color_indicator.cpp
        ${APP}/src/widget/slider.cpp
        ${APP}/src/widget/table.cpp
        ${APP}/src/widget/tabs.cpp
        ${APP}/src/widget/text.cpp
        ${APP}/src/widget/text_wrap.cpp
        ${APP}/src/widget/tree_node.cpp
        ${APP}/src/widget/window.cpp
        ${APP}/src/widget/js_canvas.cpp
        ${APP}/src/widget/lua_canvas.cpp
        ${APP}/src/widget/janet_canvas.cpp

        ./src/xframes-node.cpp

        ${OSM_STATIC_MAP_GENERATOR_SRC}
        ${LEPTONICA_SRC}

        ${SOURCE_FILES}
        ${CMAKE_JS_SRC}
)

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME}
        ${CMAKE_JS_LIB}
        ada::ada
        fmt::fmt
        nlohmann_json::nlohmann_json
        JPEG::JPEG
        PNG::PNG
        TIFF::TIFF
        CURL::libcurl

        glfw
        OpenGL::GL
        qjs
        ${LUA_LIBRARIES}
        sol2::sol2
        janet_core
)

# Include Node-API wrappers
execute_process(COMMAND node -p "require('node-addon-api').include"
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        OUTPUT_VARIABLE NODE_ADDON_API_DIR
)
string(REGEX REPLACE "[\r\n\"]" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})

target_include_directories(${PROJECT_NAME} PRIVATE
        ${NODE_ADDON_API_DIR}
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${APP}/include
        ${CMAKE_CURRENT_SOURCE_DIR}/node_modules/node-addon-api

        ${Stb_INCLUDE_DIR}

        ${DEPS}/node-addon-api
        ${DEPS}/node-api-headers/include
        ${DEPS}/IconFontCppHeaders
        ${DEPS}/ReactivePlusPlus/src/rpp
        ${DEPS}/css-color-parser-cpp
        ${DEPS}/imgui
        ${DEPS}/imgui/backends
        ${DEPS}/imgui/misc/cpp
        ${DEPS}/implot
        ${DEPS}/json/include
        ${DEPS}/yoga
        ${DEPS}/glfw/include
        ${DEPS}/osm-static-map-generator/cpp
        ${DEPS}/osm-static-map-generator/cpp/deps/leptonica/src
        ${LUA_INCLUDE_DIR}
        "${DEPS}/janet/src/include"
        "${DEPS}/janet/src/conf"
)

# define NAPI_VERSION
add_definitions(-DNAPI_VERSION=9)

if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
    # Generate node.lib
    execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})
endif()

