cmake_minimum_required(VERSION 3.29)

if (NOT DEFINED TESTING_WASM_ENGINE OR NOT TESTING_WASM_ENGINE)
  message(FATAL_ERROR "TESTING_WASM_ENGINE not specified!")
  cmake_language(EXIT 1)
endif()

if (NOT DEFINED TESTING_WASM_HTML_TEMPLATE OR NOT TESTING_WASM_HTML_TEMPLATE)
  message(FATAL_ERROR "TESTING_WASM_HTML_TEMPLATE not specified!")
  cmake_language(EXIT 1)
endif()

if (NOT DEFINED TEST_NAME OR NOT TEST_NAME)
  message(FATAL_ERROR "TEST_NAME not specified!")
  cmake_language(EXIT 1)
endif()

if (NOT DEFINED EXIT_AFTER_TEST)
  message(FATAL_ERROR "EXIT_AFTER_TEST not specified!")
  cmake_language(EXIT 1)
endif()

set(TEST_EXECUTABLE "")
set(TEST_ARGS "")

# Find position of argument after the '--' separator.
set(ARG_START 0)
math(EXPR ARG_MAX "${CMAKE_ARGC} - 1")
foreach(i RANGE ${ARG_MAX})
  if ("${CMAKE_ARGV${i}}" STREQUAL "--")
    math(EXPR ARG_START "${i} + 1")
    break()
  endif ()
endforeach()

# find test executable ".js" file and append all other arguments into TEST_ARGS
foreach(i RANGE ${ARG_START} ${ARG_MAX})
  if ("${CMAKE_ARGV${i}}" MATCHES "\.js$")
    set(TEST_EXECUTABLE "${CMAKE_ARGV${i}}")
  else ()
    list(APPEND TEST_ARGS "${CMAKE_ARGV${i}}")
  endif ()
endforeach()

if (NOT TEST_EXECUTABLE)
  message(STATUS "TEST_EXECUTABLE not specified. Skipping...")
  return()
endif()

function(generate_index_html js test_args exit_after_test url output_file)
  # Get file name from test executable
  get_filename_component(js_filename "${js}" NAME)
  set(close_window "")
  # right now we only use webgpu for the unit tests in the RenderingWebGPU module.
  set(graphics_backend "OPENGL") # default equivalent to WebGL2
  if (exit_after_test)
    set(close_window "window.close();")
  endif ()
  if ("${js}" MATCHES "WebGPU")
    set(graphics_backend "WEBGPU")
  endif ()
  configure_file("${TESTING_WASM_HTML_TEMPLATE}" "${output_file}" @ONLY)
endfunction()

function(extract_vtk_wasm_test_exit_code log_line exit_code)
  if (log_line MATCHES "vtk-wasm-test-exit-code=([-]?[0-9]+)")
    set(${exit_code} ${CMAKE_MATCH_1} PARENT_SCOPE)
  else()
    set(${exit_code} 1 PARENT_SCOPE)
  endif()
endfunction()

set(USER_PROFILE "unknown")
string(REPLACE ":" "" USER_PROFILE "${TEST_NAME}")
set(USER_PROFILE_DIR "${TEST_OUTPUT_DIR}/${USER_PROFILE}")

set(HTTP_SERVER_URL "http://localhost:8000")
if (EXISTS "${TEST_OUTPUT_DIR}/vtkhttp.lock")
  # The vtkhttp.lock has json. it is written by `server.js`.
  file(READ "${TEST_OUTPUT_DIR}/vtkhttp.lock" HTTP_LOCK)
  # pull address and port
  string(JSON HTTP_SERVER_ADDRESS GET "${HTTP_LOCK}" address)
  string(JSON HTTP_SERVER_PORT GET "${HTTP_LOCK}" port)
  set(HTTP_SERVER_URL "http://${HTTP_SERVER_ADDRESS}:${HTTP_SERVER_PORT}")
else ()
  message(FATAL_ERROR "${TEST_OUTPUT_DIR}/vtkhttp.lock file does not exist!")
  cmake_language(EXIT 1)
endif()

# Create user profile directory
file(MAKE_DIRECTORY "${USER_PROFILE_DIR}")

# Generate HTML for unit test
set(TEST_HTML "${USER_PROFILE_DIR}/test.html")
set(TEST_HTML_URL "file://${TEST_HTML}")
generate_index_html("${TEST_EXECUTABLE}" "${TEST_ARGS}" "${EXIT_AFTER_TEST}" "${HTTP_SERVER_URL}" "${TEST_HTML}")
set(TEST_HTML_URL "${HTTP_SERVER_URL}/${USER_PROFILE}/test.html")

message(STATUS "TEST_EXECUTABLE=${TEST_EXECUTABLE}")
message(STATUS "TEST_ARGS=${TEST_ARGS}")
message(STATUS "USER_PROFILE_DIR=${USER_PROFILE_DIR}")
message(STATUS "HTTP_SERVER_URL=${HTTP_SERVER_URL}")

set(IMPLICIT_ENGINE_ARGS "")
if (TESTING_WASM_ENGINE MATCHES "chrome|chromium|Google Chrome")
  set(IMPLICIT_ENGINE_ARGS
    "--disable-application-cache"
    "--disable-extensions"
    "--disable-notifications"
    "--disable-restore-session-state"
    "--new-window"
    "--no-default-browser-check"
    "--no-first-run"
    "--enable-logging=stderr"
    "--v=INFO:CONSOLE"
    "--user-data-dir=${USER_PROFILE_DIR}"
    "--enable-features=WebAssemblyExperimentalJSPI")
  if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
    list(APPEND IMPLICIT_ENGINE_ARGS "--enable-features=Vulkan")
    list(APPEND IMPLICIT_ENGINE_ARGS "--enable-unsafe-webgpu")
    list(APPEND IMPLICIT_ENGINE_ARGS "--use-angle=Vulkan")
  endif()
endif()

if (IS_EXECUTABLE "${TESTING_WASM_ENGINE}")
  execute_process(
    COMMAND ${TESTING_WASM_ENGINE} ${IMPLICIT_ENGINE_ARGS} ${TESTING_WASM_ENGINE_ARGS} ${TEST_HTML_URL}
    OUTPUT_VARIABLE ENGINE_ERROR_OUTPUT
    ERROR_VARIABLE ENGINE_ERROR_OUTPUT
    ECHO_OUTPUT_VARIABLE
    ECHO_ERROR_VARIABLE
    COMMAND_ECHO STDOUT
  )

  set(EXIT_CODE 1)
  if (ENGINE_ERROR_OUTPUT)
    extract_vtk_wasm_test_exit_code(${ENGINE_ERROR_OUTPUT} EXIT_CODE)
  endif()
else ()
  message(FATAL_ERROR "TESTING_WASM_ENGINE: ${TESTING_WASM_ENGINE} is not an executable!")
  set(EXIT_CODE 1)
endif ()

# Cleanup user profile directory
file(REMOVE_RECURSE "${USER_PROFILE_DIR}")

cmake_language(EXIT ${EXIT_CODE})
