include_guard(GLOBAL)

#[[
ERROR > WARN > INFO > DEBUG > TRACE
PANIC, FATAL, NOTICE are always shown in the log. Whether they are displayed
is dependent on the ixm::print::quiet property
]]

function (ixm_log_cache)
  if (DEFINED CACHE{ixm::log::check})
    return()
  endif()
  set(ixm::log::trace DEBUG INFO WARN ERROR CACHE INTERNAL "")
  set(ixm::log::debug INFO WARN ERROR CACHE INTERNAL "")
  set(ixm::log::info WARN ERROR CACHE INTERNAL "")
  set(ixm::log::warn ERROR CACHE INTERNAL "")
  set(ixm::log::check PANIC FATAL NOTICE ERROR WARN INFO DEBUG TRACE CACHE INTERNAL "")
  set(ixm::log::always FATAL PANIC NOTICE)
endfunction()

function (log level)
  ixm_log_cache()
  if (NOT (level IN_LIST ixm::log::check))
    message(FATAL_ERROR "log(${level}) is not a supported logging level")
  endif()
  aspect(GET log:level AS current)
  if (level IN_LIST ixm::log::always) # Skip this logic block
  elseif (level STREQUAL "TRACE" AND current IN_LIST ixm::log::trace)
    return()
  elseif (level STREQUAL "DEBUG" AND current IN_LIST ixm::log::debug)
    return()
  elseif (level STREQUAL "INFO" AND current IN_LIST ixm::log::info)
    return()
  elseif (level STREQUAL "WARN" AND current IN_LIST ixm::log::warn)
    return()
  endif()
  if (level STREQUAL "TRACE")
    set(color lemon-chiffon)
  elseif (level STREQUAL "DEBUG")
    set(color medium-spring-green)
  elseif (level STREQUAL "INFO")
    set(color steel-blue)
  elseif (level STREQUAL "WARN")
    set(color gold)
  elseif (level STREQUAL "ERROR")
    set(color crimson)
  elseif (level STREQUAL "FATAL")
    set(color red)
  elseif (level STREQUAL "PANIC")
    set(color tomato)
  elseif (level STREQUAL "NOTICE")
  endif()
  aspect(GET log:strftime AS strftime)
  string(TIMESTAMP timestamp "${strftime}")
  list(JOIN ARGN " " message)
  ixm_log_print("${timestamp}" "${level}" "${message}" "${color}")
  ixm_log_file("${timestamp}" "${level}" "${message}")
  ixm_log_json("${timestamp}" "${level}" "${message}")
endfunction()

function (ixm_log_print timestamp level message)
  list(GET ARGN 0 color)
  aspect(GET log:color)
  if (NOT log:color)
    unset(.${color})
    unset(.reset)
  endif()
  set(errors FATAL PANIC)
  set(status STATUS)
  if (level IN_LIST errors)
    set(status FATAL_ERROR)
  elseif (level STREQUAL "NOTICE" AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
    set(status NOTICE)
  endif()
  message(${status} "${.${color}}[${timestamp}] ${level}: ${message}${.reset}")
endfunction()

function (ixm_log_json timestamp level message)
  aspect(GET path:log AS directory)
  assign(filename ? PROJECT_NAME : ixm)
  list(APPEND elements [["time":"@timestamp@"]])
  list(APPEND elements [["level":"@level@"]])
  list(APPEND elements [["message":"@message@"]])
  list(APPEND elements [["project":"@PROJECT_NAME@"]])
  list(APPEND elements [["file": "@CMAKE_CURRENT_LIST_FILE@"]])
  list(JOIN elements "," object)
  string(CONFIGURE "{${object}}" text @ONLY)
  file(APPEND "${directory}/${filename}.jsonl" "${text}\n")
endfunction()

function (ixm_log_file timestamp level message)
  aspect(GET path:log AS directory)
  assign(filename ? PROJECT_NAME : ixm)
  file(APPEND "${directory}/${filename}.log"
    "[${timestamp}] ${level}: ${message}\n")
endfunction()
