if(${CMAKE_VERSION} VERSION_LESS 3.17.0)
  set(MYX_CMAKE_LIB_UNCRUSTIFY_DIR_BACKPORT "${CMAKE_CURRENT_LIST_DIR}")
endif()

find_program(UNCRUSTIFY_EXE NAMES uncrustify)

function(myx_uncrustify TARGET_NAME)
  if(${CMAKE_VERSION} VERSION_LESS 3.17.0)
    set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${MYX_CMAKE_LIB_UNCRUSTIFY_DIR_BACKPORT})
  endif()

  set(options)
  set(oneValueArgs CONFIG)
  set(multiValueArgs)
  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(NOT ARG_CONFIG)
    set(ARG_CONFIG "${PROJECT_SOURCE_DIR}/uncrustify.cfg")
  endif()

  if(NOT EXISTS ${ARG_CONFIG})
    myx_message_notice("MyxCMake: uncrustify config is not found")
    return()
  endif()

  if(NOT UNCRUSTIFY_EXE)
    myx_message_notice("MyxCMake: uncrustify executable is not found")
    return()
  endif()

  get_filename_component(CONFIG_DIR ${ARG_CONFIG} DIRECTORY)
  if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CONFIG_DIR}")
    myx_message("MyxCMake: skip uncrustify for project ${PROJECT_NAME}")
    return()
  endif()

  if(NOT TARGET myx-uncrustify)
    add_custom_target(myx-uncrustify)
  endif()
  if(NOT TARGET myx-uncrustify-check)
    add_custom_target(myx-uncrustify-check)
  endif()
  if(NOT TARGET myx-uncrustify-append-comments)
    add_custom_target(myx-uncrustify-append-comments)
  endif()

  # Динамически сгенерированные файлы исключаются
  get_target_property(target_type ${TARGET_NAME} TYPE)
  if((${target_type} STREQUAL "INTERFACE_LIBRARY") AND (${CMAKE_VERSION} VERSION_LESS 3.17.0))
    get_target_property(target_sources ${TARGET_NAME} INTERFACE_SOURCES)
    if(target_sources)
      list(APPEND all_sources ${target_sources})
    endif()
  else()
    get_target_property(target_sources ${TARGET_NAME} SOURCES)
    if(target_sources)
      list(APPEND all_sources ${target_sources})
    endif()
  endif()

  foreach(iter ${all_sources})
    string(FIND ${iter} ${CMAKE_BINARY_DIR} pos)
    if(pos EQUAL -1)
      list(APPEND sources ${iter})
    endif()
  endforeach()

  set(fixed_config ${PROJECT_BINARY_DIR}/uncrustify-${TARGET_NAME}.cfg)
  add_custom_command(OUTPUT ${fixed_config}
                     DEPENDS ${ARG_CONFIG}
                     COMMAND ${UNCRUSTIFY_EXE} --update-config-with-doc
                                               -c ${ARG_CONFIG} -o ${fixed_config})
  list(APPEND options -c ${fixed_config})
  # cmake-format: off
  add_custom_target(${TARGET_NAME}-uncrustify-check
    DEPENDS ${fixed_config}
    COMMAND ${UNCRUSTIFY_EXE} ${options} --check ${sources})

  list(APPEND options --replace --no-backup)
  add_custom_target(${TARGET_NAME}-uncrustify
    DEPENDS ${fixed_config}
    COMMAND ${UNCRUSTIFY_EXE} ${options} --mtime ${sources})

  add_custom_target(${TARGET_NAME}-uncrustify-append-comments
    DEPENDS ${fixed_config}
    COMMAND ${UNCRUSTIFY_EXE} ${options}
            --set cmt_insert_class_header=${CMAKE_CURRENT_FUNCTION_LIST_DIR}/classheader.txt
            --set cmt_insert_file_footer=${CMAKE_CURRENT_FUNCTION_LIST_DIR}/filefooter.txt
            --set cmt_insert_file_header=${CMAKE_CURRENT_FUNCTION_LIST_DIR}/fileheader.txt
            --set cmt_insert_func_header=${CMAKE_CURRENT_FUNCTION_LIST_DIR}/funcheader.txt
            --set cmt_insert_before_ctor_dtor=true --mtime ${sources})
  # cmake-format: on

  add_dependencies(myx-uncrustify ${TARGET_NAME}-uncrustify)
  add_dependencies(myx-uncrustify-check ${TARGET_NAME}-uncrustify-check)
  add_dependencies(myx-uncrustify-append-comments ${TARGET_NAME}-uncrustify-append-comments)
endfunction()