option(PSEMEK_PACKAGE_MODE "Enable packaging mode" OFF)
set(PSEMEK_PACKAGE_OUTPUT_PATH "" CACHE STRING "Packaging output path")
set(PSEMEK_PACKAGE_VERSION_SUFFIX "" CACHE STRING "Packaging version suffix")

if(PSEMEK_PACKAGE_MODE)
	if(WIN32)
		set(PSEMEK_PACKAGE_SUFFIX_RAW windows)
	elseif(APPLE)
		set(PSEMEK_PACKAGE_SUFFIX_RAW mac)
	elseif(ANDROID)
		set(PSEMEK_PACKAGE_SUFFIX_RAW android)
	elseif(UNIX)
		set(PSEMEK_PACKAGE_SUFFIX_RAW linux)
	else()
		message(FATAL "Uknown system for packaging")
	endif()
	set(PSEMEK_PACKAGE_SUFFIX ${PSEMEK_PACKAGE_SUFFIX_RAW} CACHE INTERNAL "Packaging suffix" FORCE)

	set(PSEMEK_PACKAGE_LINK_FLAGS_RAW)
	if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
		list(APPEND PSEMEK_PACKAGE_LINK_FLAGS_RAW "-static-libgcc" "-static-libstdc++")
	endif()
	set(PSEMEK_PACKAGE_LINK_FLAGS ${PSEMEK_PACKAGE_LINK_FLAGS_RAW} CACHE INTERNAL "Packaging CXX flags" FORCE)

	set(PSEMEK_COPY_FILES_RAW)
endif()

function(psemek_package_output_path target outvar)
	if(NOT PSEMEK_PACKAGE_MODE)
		message(FATAL "psemek_package_output_path must only be called during packaging")
	endif()

	if(ANDROID)
		set(_PACKAGE_EXTENSION apk)
	else()
		set(_PACKAGE_EXTENSION zip)
	endif()

	set(${outvar} "${CMAKE_CURRENT_LIST_DIR}/${PSEMEK_PACKAGE_OUTPUT_PATH}/${target}${PSEMEK_PACKAGE_VERSION_SUFFIX}-${PSEMEK_PACKAGE_SUFFIX}.${_PACKAGE_EXTENSION}" PARENT_SCOPE)
endfunction()

function(psemek_add_executable_impl target is_application)
	if((NOT PSEMEK_PACKAGE_MODE) OR PSEMEK_PACKAGE_TARGET)
		if(${PSEMEK_PACKAGE_AS_LIBRARY} AND ${is_application})
			add_library(${target} SHARED ${ARGN})
		else()
			add_executable(${target} ${ARGN})
		endif()

		target_link_libraries(${target} PUBLIC psemek)
		if(${is_application})
			target_link_libraries(${target} PUBLIC
				"-Wl,--whole-archive $<TARGET_FILE:${PSEMEK_BACKEND_LIBRARY}> -Wl,--no-whole-archive"
				${PSEMEK_BACKEND_LIBRARY})
		endif()

		install(TARGETS ${target})

		if(PSEMEK_PACKAGE_MODE)
			target_link_options(${target} PUBLIC ${PSEMEK_PACKAGE_LINK_FLAGS})

			target_compile_definitions(${target} PUBLIC "-DPSEMEK_PACKAGE_MODE")

			if(UNIX AND (NOT APPLE))
				set_target_properties(${target} PROPERTIES
					BUILD_RPATH "."
				)
			endif()

			if(UNIX AND (NOT APPLE) AND (NOT ANDROID))
				add_custom_command(TARGET ${target} POST_BUILD
					COMMAND chrpath -r . $<TARGET_FILE:${target}>
				)
			endif()

			psemek_package_output_path(${target} _OUTPUT_PATH)

			if(NOT ANDROID)
				get_filename_component(_OUTPUT_DIRECTORY "${_OUTPUT_PATH}" DIRECTORY)

				set(_COPY_FILES $<TARGET_FILE:${target}> ${PSEMEK_PACKAGE_COPY_FILES})

				if(PSEMEK_GRAPHICS_API STREQUAL WEBGPU)
					list(APPEND _COPY_FILES ${PSEMEK_PACKAGE_COPY_FILES_WGPU})
				endif()

				if(PSEMEK_USE_FREETYPE)
					list(APPEND _COPY_FILES ${PSEMEK_PACKAGE_COPY_FILES_FREETYPE})
				endif()

				add_custom_command(TARGET ${target} POST_BUILD
					COMMAND echo Packaging target ${target} into ${_OUTPUT_PATH}
					COMMAND mkdir -pv "${_OUTPUT_DIRECTORY}"
					COMMAND zip -v "${_OUTPUT_PATH}" -j ${_COPY_FILES}
					COMMAND echo Packaged target ${target} into ${_OUTPUT_PATH}
				)
			else()
				if("${PSEMEK_APPLICATION_NAME}" STREQUAL "")
					message(FATAL_ERROR "PSEMEK_APPLICATION_NAME cannot be empty when building for android")
				endif()
				add_custom_command(TARGET ${target} POST_BUILD
					COMMAND ${PSEMEK_PACKAGE_HELPER} "${target}" "${PSEMEK_APPLICATION_NAME}" "${_OUTPUT_PATH}"
				)
			endif()
		endif()
	endif()
endfunction()

function(psemek_add_executable target)
	psemek_add_executable_impl(${target} FALSE ${ARGN})
endfunction()

function(psemek_add_application target)
	psemek_add_executable_impl(${target} TRUE ${ARGN})
endfunction()

function(psemek_add_dev_application target)
	if(NOT PSEMEK_PACKAGE_MODE)
		psemek_add_application(${target} ${ARGN})
	endif()
endfunction()

function(psemek_add_build_tool target link_psemek)
	if((NOT PSEMEK_PACKAGE_MODE) OR PSEMEK_PACKAGE_HOST)
		add_executable(${target} ${ARGN})

		if(${link_psemek})
			target_link_libraries(${target} PUBLIC psemek)
		endif()

		if(PSEMEK_PACKAGE_MODE)
			target_compile_definitions(${target} PUBLIC "-DPSEMEK_PACKAGE_MODE")

			install(TARGETS ${target} RUNTIME DESTINATION bin)
		endif()
	else()
		find_file(_LOCATION ${target} PATHS "${PSEMEK_PACKAGE_TOOLS_PATH}/bin" NO_CACHE)
		message(STATUS "Found ${target}: ${_LOCATION}")
		if(NOT _LOCATION)
			message(FATAL_ERROR "Could not locate ${target} build tool in ${PSEMEK_PACKAGE_TOOLS_PATH}")
		endif()
		add_executable(${target} IMPORTED GLOBAL)
		set_target_properties(${target} PROPERTIES IMPORTED_LOCATION ${_LOCATION})
	endif()
endfunction()

function(psemek_add_dev_tool target link_psemek)
	if(NOT PSEMEK_PACKAGE_MODE)
		add_executable(${target} ${ARGN})

		if(${link_psemek})
			target_link_libraries(${target} PUBLIC psemek)
		endif()
	endif()
endfunction()

function(psemek_add_library target)
	add_library(${target} ${ARGN})

	set(_GUARD_SOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/nosource_library_guard.cpp")
	target_sources(${target} PRIVATE ${_GUARD_SOURCE_LOCATION})
	if(NOT (EXISTS "${_GUARD_SOURCE_LOCATION}"))
		file(TOUCH "${_GUARD_SOURCE_LOCATION}")
	endif()

	if(PSEMEK_PACKAGE_MODE)
		target_compile_definitions(${target} PUBLIC "-DPSEMEK_PACKAGE_MODE")
	endif()
endfunction()

function(psemek_add_winrc target path)
	if(WIN32 AND (TARGET ${target}))
		get_target_property(OUT_DIR ${target} BINARY_DIR)

		set(_IN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${path}")

		file(MAKE_DIRECTORY "${OUT_DIR}/winrc")
		set(_OUT_FILE "${OUT_DIR}/winrc/res.o")

		add_custom_command(OUTPUT "${_OUT_FILE}"
			COMMAND ${CMAKE_RC_COMPILER} "${_IN_FILE}" "${_OUT_FILE}"
			DEPENDS psemek-resource-compiler "${_IN_FILE}"
			WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")

		target_sources(${target} PRIVATE "${_OUT_FILE}")
	endif()
endfunction()

function(psemek_package_files target)
	if(PSEMEK_PACKAGE_MODE)
		if(PSEMEK_PACKAGE_TARGET)
			if(ANDROID)
				add_custom_command(TARGET ${target} POST_BUILD
					WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
					COMMAND ${PSEMEK_COPY_FILES} ${ARGN}
				)
			else()
				psemek_package_output_path(${target} _OUTPUT_PATH)

				add_custom_command(TARGET ${target} POST_BUILD
					WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
					COMMAND zip -v "${_OUTPUT_PATH}" -r ${ARGN}
				)
			endif()
		endif()
	else()
		foreach(_FILE ${ARGN})
			get_filename_component(_DIR ${_FILE} DIRECTORY)
			add_custom_command(TARGET ${target} POST_BUILD
				WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
				COMMAND "mkdir" "-pv" "${CMAKE_CURRENT_BINARY_DIR}/${_DIR}"
			)
			add_custom_command(TARGET ${target} POST_BUILD
				WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
				COMMAND "cp" "-rv" ${_FILE} "${CMAKE_CURRENT_BINARY_DIR}/${_DIR}"
			)
		endforeach()
	endif()
endfunction()
