local M = {}

-- 导入依赖模块
local sched = sched or require("aubo").sched
local welding_common = require("welding_common")
local welding_config = require("welding_config")
local welding_arc = require("welding_arc")
local welding_motion = require("welding_motion")
local welding_weave = require("welding_weave")
local welding_utils = require("welding_utils")
local welding_helpers = require("welding_helpers")
local welding_laser = require("welding_laser")
local welding_resume = require("welding_resume")

-- 多层多道工艺处理
function M.multiProcessProcessing(multi_channel_data, params, state)
	-- 设置机器人环境
	local _ENV = sched.select_robot(1)
	local instructions = {}

	-- 续弧信息只允许消费一次：优先用于第一段需要的圆弧指令。
	-- 这里做一个本地“懒加载 + 一次性消费”包装，避免在多段循环里重复读取并重复应用。
	local resume_arc_continuation_cache_ = nil
	local function consumeResumeArcContinuationOnce()
		if resume_arc_continuation_cache_ == nil then
			resume_arc_continuation_cache_ = welding_resume.consumeResumeArcContinuation
					and welding_resume.consumeResumeArcContinuation()
				or false
		end
		if resume_arc_continuation_cache_ and resume_arc_continuation_cache_ ~= false then
			local v = resume_arc_continuation_cache_
			resume_arc_continuation_cache_ = false
			return v
		end
		return nil
	end

	-- 验证多层焊接数据格式
	local multi_node_start = multi_channel_data[1]
	local multi_node_end = multi_channel_data[#multi_channel_data]
	if multi_node_start.action_.event ~= 8 or multi_node_end.action_.event ~= 9 then
		log_error(
			welding_common.log_prefix
				.. "Multi channel data does not meet the requirements, it is not the beginning and end of multiple channels"
		)
		return {}
	end

	-- 提取有效动作（跳过开始和结束动作）
	local actions = {}
	for i = 2, #multi_channel_data - 1 do
		local tmp_action = multi_channel_data[i].action_
		-- 多层多道处理线激光点位
		if tmp_action.roadpoints[1].type ~= "Common" then
			for j, rp in ipairs(tmp_action.roadpoints) do
				local data = welding_laser.getLaserData(rp.uuid)
				local real_q, err = welding_motion.inverseSolutionSuccess(data.joint_angles, data.tcp_pose)
				if err == 0 then
					rp.tcp_pose = data.tcp_pose
					rp.q = real_q
				else
					textmsg(welding_common.tr(welding_common.ERROR_ENUM.LASER_INVERSE_KINEMATICS_FAILED))
					log_error(welding_common.log_prefix .. "InverseKinematics failed for laser point")
					return
				end
			end
		end
		table.insert(actions, tmp_action)
	end
	-- 检查 actions 是否有效
	if not actions or #actions == 0 then
		log_error(welding_common.log_prefix .. "No actions available for processing")
		return {}
	end

	-- 多层多道开始之后是否有空走点
	local cache_has_start_air_move = actions[1].event == 0
	if not cache_has_start_air_move then
		table.insert(actions, 1, {
			event = 0,
			index = multi_node_start.action_.index,
			real_action = false,
		})
		log_info(welding_common.log_prefix .. "Multipass start prepend synthetic air-move point")
	end
	-- 多层多道结束之前是否有空走点
	local cache_has_end_air_move = actions[#actions].event == 0
	if not cache_has_end_air_move then
		table.insert(actions, {
			event = 0,
			index = multi_node_end.action_.index,
			real_action = false,
		})
		log_info(welding_common.log_prefix .. "Multipass end append synthetic air-move point")
	end

	-- 处理反向模式
	local actions_return = {}
	local multi_node_start_action = multi_node_start.action_
	if
		multi_node_start_action.multi_channel_parameters
		and multi_node_start_action.multi_channel_parameters.mp_is_return_mode
	then
		-- 反向插入元素
		for i = #actions, 1, -1 do
			local action = actions[i]
			if action.event == 2 then
				-- 圆弧点位交换
				local actions_temporary = welding_utils.deepCopy(action)
				actions_temporary.roadpoints[1] = action.roadpoints[3]
				actions_temporary.roadpoints[2] = action.roadpoints[2]
				actions_temporary.roadpoints[3] = action.roadpoints[1]
				table.insert(actions_return, actions_temporary)
			else
				-- 非圆弧事件直接推入
				table.insert(actions_return, action)
			end
		end
	end

	-- 获取多层多道参数
	local multi_layer_configuration = multi_node_start_action.multi_channel_parameters
	if #multi_layer_configuration.layers_parameter.channel_parameter == 0 then
		welding_common.showErrorMessage(welding_common.ERROR_ENUM.MULTIPLE_CHANNELS_EMPTY)
		return
	end

	-- 准备焊接路径
	local src_segs = {}
	local old_start_point = {}
	local mp_is_return_mode = multi_layer_configuration.mp_is_return_mode

	local execute_actions = actions
	local has_start_air_move = cache_has_start_air_move
	local has_end_air_move = cache_has_end_air_move

	-- 遍历每一道
	for w = 1, #multi_layer_configuration.layers_parameter.channel_parameter do
		log_info(welding_common.log_prefix .. "Start traversing the path " .. w)
		local channel_parameter = multi_layer_configuration.layers_parameter.channel_parameter[w]
		-- 每一道最后一个焊接点
		local last_weld_end_pose = nil
		if channel_parameter.enable == false then
			goto continue
		end
		welding_arc.syncProgramPoint()

		if mp_is_return_mode then
			if w % 2 == 1 then
				execute_actions = actions
				has_start_air_move = cache_has_start_air_move
				has_end_air_move = cache_has_end_air_move
			else
				execute_actions = actions_return
				has_start_air_move = cache_has_end_air_move
				has_end_air_move = cache_has_start_air_move
			end
		end

		-- 处理每个动作
		for i = 1, #execute_actions do
			local action_data = execute_actions[i]
			local resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
			if not action_data then
				log_error(welding_common.log_prefix .. "Action at index " .. i .. " has no action_ field")
				goto continue_inner
			end

			-- 检查是否有下一个元素
			local next_action = (i < #execute_actions) and execute_actions[i + 1] or nil

			if (i == #execute_actions or action_data.event == 0) and #src_segs ~= 0 then
				-- 处理 event 0
				local blender = {
					type = "Auto",
					blend_radius = multi_layer_configuration.layers_parameter.transition_radius,
				}
				-- 计算偏移量
				local offset = welding_helpers.createOffset(
					channel_parameter.y,
					channel_parameter.z,
					channel_parameter.A,
					channel_parameter.B
				)

				-- 确定焊接类型
				local MP_Type = multi_layer_configuration.layers_parameter.path_weldtype

				local h_plane = multi_layer_configuration.mp_is_h_plane
				local auto_frame = multi_layer_configuration.mp_is_auto_mode
				local auto_optimize = multi_layer_configuration.mp_is_auto_optimize
				-- 自动设置op点
				local multiple_paths
				if auto_frame then
					multiple_paths = welding_helpers.multiPath(
						h_plane,
						src_segs,
						MP_Type,
						auto_frame,
						blender,
						offset,
						auto_optimize,
						{},
						{}
					)
				else
					local o_point, o_point_ok = welding_motion.inverseSolutionSuccess(
						multi_layer_configuration.mp_o_point.q,
						multi_layer_configuration.mp_o_point.tcp_pose
					)
					local p_point, p_point_ok = welding_motion.inverseSolutionSuccess(
						multi_layer_configuration.mp_p_point.q,
						multi_layer_configuration.mp_p_point.tcp_pose
					)

					if not o_point_ok or not p_point_ok then
						if not o_point_ok then
							textmsg(welding_common.tr(welding_common.ERROR_ENUM.MP_O_INVERSE_FAILED))
							log_error(welding_common.log_prefix .. "Inverse solution failed for mp_o_point")
						end
						if not p_point_ok then
							textmsg(welding_common.tr(welding_common.ERROR_ENUM.MP_P_INVERSE_FAILED))
							log_error(welding_common.log_prefix .. "Inverse solution failed for mp_p_point")
						end
						return false -- 或处理错误
					end

					multiple_paths = welding_helpers.multiPath(
						h_plane,
						src_segs,
						MP_Type,
						auto_frame,
						blender,
						offset,
						auto_optimize,
						multi_layer_configuration.mp_o_point.tcp_pose,
						multi_layer_configuration.mp_p_point.tcp_pose
					)
				end
				src_segs = {} -- 直接覆盖原表，清空所有数据
				old_start_point = {}

				local segs = {}

				if multiple_paths[1] == 0 then
					segs = multiple_paths[2]
				else
					log_error(welding_common.log_prefix .. "Failed to obtain multiple sets of data")
				end

				-- 获取焊接速度
				local motion = channel_parameter.craft_param.motion
				local speed = motion.welding_speed or 0
				local welder_param = channel_parameter.craft_param.welder
				if #segs ~= 0 then
					last_weld_end_pose = welding_motion.formatPose(segs[#segs]["end"])
					if not has_start_air_move then
						local lift = tonumber(params.offset_distance) or 0
						if lift > 0 then
							local start_pose = welding_motion.formatPose(segs[1]["start"])
							local lifted_start_pose = poseTrans(start_pose, { 0, 0, -lift, 0, 0, 0 })
							resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
							local start_line_num = segs[1]["start_rownum"]
							welding_utils.auboSetLabel(start_line_num)
							welding_motion.generateMoveLine(
								lifted_start_pose,
								params.motion_parameters.tool_speed,
								params,
								state,
								false,
								motion.weld_type,
								true,
								execute_motion
							)
							welding_arc.syncProgramPoint()
						end
					end

					resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
					local line_num = segs[1]["start_rownum"]
					welding_utils.auboSetLabel(line_num)
					welding_motion.generateMoveLine(
						welding_motion.formatPose(segs[1]["start"]),
						params.motion_parameters.tool_speed,
						params,
						state,
						false,
						motion.weld_type,
						true,
						execute_motion
					)
					welding_arc.syncProgramPoint()
				end

				resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
				if state == "raw_path_weld" and #segs ~= 0 and resume_state ~= 1 then
					--更新焊接参数
					welding_config.updateWeldingParameters(
						welder_param.current or 0,
						welder_param.voltage or 0,
						welder_param.off_voltage or 0,
						welder_param.off_current or 0,
						welder_param.arc_extinguishing_time or 0,
						welder_param.delivery_time or 0,
						welder_param.arc_voltage or 0,
						welder_param.arc_current or 0,
						welder_param.starting_arc_time or 0
					)
					--起弧
					welding_arc.startArc()
				end

				if state ~= "raw_point_sim" and (motion.weave == 1 or motion.weave == 2) then
					local weave_param = welding_weave.getSwingParams(motion)
					log_info(welding_common.log_prefix .. "weave start")
					weaveStart(weave_param)
				end

				resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
				if state ~= "raw_point_sim" and motion.weave == 4 then
					for seg_idx = 1, #segs do
						local seg = segs[seg_idx]
						if seg["line"] then
							local line_num_start = seg["start_rownum"]
							welding_utils.auboSetLabel(line_num_start)
							welding_weave.handleStraightWeave(
								motion,
								welding_motion.formatPose(seg["start"]),
								welding_motion.formatPose(seg["end"]),
								params,
								state
							)
							local line_num_end = seg["end_rownum"]
							welding_utils.auboSetLabel(line_num_end)
						else
							local points = {
								welding_motion.formatPose(seg["start"]),
								seg["via"],
								seg["end"],
							}
							local line_num_start = seg["start_rownum"]
							welding_utils.auboSetLabel(line_num_start)
							welding_weave.handleCircularWeave(motion, points, params, state)
							local line_num_end = seg["end_rownum"]
							welding_utils.auboSetLabel(line_num_end)
						end
					end
				elseif state ~= "raw_point_sim" and motion.weave == 3 then
					for seg_idx = 1, #segs do
						local seg = segs[seg_idx]
						if seg["line"] then
							local line_num_start = seg["start_rownum"]
							welding_utils.auboSetLabel(line_num_start)
							welding_weave.linearCrescentOscillation(
								motion,
								welding_motion.formatPose(seg["start"]),
								welding_motion.formatPose(seg["end"]),
								params,
								state
							)
							local line_num_end = seg["end_rownum"]
							welding_utils.auboSetLabel(line_num_end)
						else
							local points = {}
							table.insert(points, seg["start"])
							table.insert(points, seg["via"])
							table.insert(points, seg["end"])
							--圆弧月牙摆动
						end
					end
				else
					-- 生成移动指令
					for seg_idx = 1, #segs do
						resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
						local seg = segs[seg_idx]
						local is_last_seg = (seg_idx == #segs)

						if seg["line"] then
							local line_num_end = seg["end_rownum"]
							local end_pose = welding_motion.formatPose(seg["end"])
							local line_execute_motion = execute_motion
							welding_utils.auboSetLabel(line_num_end)
							welding_motion.generateMoveLine(
								end_pose,
								speed,
								params,
								state,
								is_last_seg,
								motion.weld_type,
								true,
								execute_motion
							)

							-- 干跑命中恢复点后，标签已经推进，真实运动需要补执行一次但不能重复计点。
							resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
							if not line_execute_motion and execute_motion then
								welding_motion.generateMoveLine(
									end_pose,
									speed,
									params,
									state,
									is_last_seg,
									motion.weld_type,
									false,
									true
								)
							end
						else
							local line_num_start = seg["start_rownum"]
							welding_utils.auboSetLabel(line_num_start)
							local via_pose = welding_motion.formatPose(seg["via"])
							local end_pose = welding_motion.formatPose(seg["end"])
							local resume_arc_applied = false
							if execute_motion then
								local resume_arc = consumeResumeArcContinuationOnce()
								if
									resume_arc
									and type(resume_arc.via_pose) == "table"
									and type(resume_arc.end_pose) == "table"
								then
									via_pose = resume_arc.via_pose
									end_pose = resume_arc.end_pose
									resume_arc_applied = true
									log_info(
										welding_common.log_prefix
											.. "multipass apply resume moveC continuation in move arc"
									)
								end
							end
							if not resume_arc_applied then
								welding_motion.generateMoveLine(
									welding_motion.formatPose(seg["start"]),
									speed,
									params,
									state,
									false,
									motion.weld_type,
									true,
									execute_motion
								)
							end

							-- 圆弧起点干跑可能正好命中恢复点；此时要先恢复起弧，再替换成剩余圆弧执行。
							resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
							if not resume_arc_applied and execute_motion then
								local resume_arc = consumeResumeArcContinuationOnce()
								if
									resume_arc
									and type(resume_arc.via_pose) == "table"
									and type(resume_arc.end_pose) == "table"
								then
									via_pose = resume_arc.via_pose
									end_pose = resume_arc.end_pose
									resume_arc_applied = true
									log_info(
										welding_common.log_prefix
											.. "multipass apply resume moveC continuation after arc start label"
									)
								end
							end
							welding_motion.generateMoveArc(
								via_pose,
								end_pose,
								speed,
								params,
								state,
								is_last_seg,
								motion.weld_type,
								true,
								execute_motion
							)
						end
					end
				end

				--熄弧
				resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
				if state == "raw_path_weld" and #segs ~= 0 and resume_state ~= 1 then
					welding_arc.stopArc()
				end
				resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
				if state ~= "raw_point_sim" and (motion.weave == 1 or motion.weave == 2) then
					log_info(welding_common.log_prefix .. "weave end")
					weaveEnd()
				end

				-- 添加最后一段移动
				if action_data.event == 0 and action_data.roadpoints and #action_data.roadpoints > 0 then
					resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
					local line_num = action_data.index
					welding_utils.auboSetLabel(line_num)
					welding_motion.generateMoveLine(
						welding_motion.formatPose(action_data.roadpoints[1].pose or action_data.roadpoints[1].tcp_pose),
						params.motion_parameters.tool_speed,
						params,
						state,
						false,
						motion.weld_type,
						true,
						execute_motion
					)
				elseif action_data.real_action == nil then
					log_error(welding_common.log_prefix .. "Action_data at index " .. i .. " has no roadpoints")
				end
			elseif action_data.event == 0 then
				local motion = channel_parameter.craft_param.motion
				if action_data.roadpoints and #action_data.roadpoints > 0 then
					resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
					local line_num = action_data.index
					welding_utils.auboSetLabel(line_num)
					welding_motion.generateMoveLine(
						welding_motion.formatPose(action_data.roadpoints[1].pose or action_data.roadpoints[1].tcp_pose),
						params.motion_parameters.tool_speed,
						params,
						state,
						false,
						motion.weld_type,
						true,
						execute_motion
					)
				elseif action_data.real_action == nil then
					log_error(welding_common.log_prefix .. "Action_data at index " .. i .. " has no roadpoints")
				end
			elseif action_data.event == 1 and next_action then
				-- 处理 event 1
				if next_action.event == 1 then
					local start_point = action_data.roadpoints
							and #action_data.roadpoints > 0
							and action_data.roadpoints[1].pose
						or action_data.roadpoints[1].tcp_pose
						or nil
					local end_point = next_action.roadpoints
							and #next_action.roadpoints > 0
							and next_action.roadpoints[1].pose
						or next_action.roadpoints[1].tcp_pose
						or nil
					local start_rownum = action_data.index
					local end_rownum = next_action.index

					if start_point and end_point then
						table.insert(
							src_segs,
							welding_helpers.createSegment(
								true,
								start_point,
								{},
								end_point,
								start_rownum,
								end_rownum,
								{},
								{},
								{}
							)
						)
					else
						log_error(welding_common.log_prefix .. "Missing roadpoints for event 1 processing")
					end
				end
			elseif action_data.event == 2 then
				-- 处理 event 2
				local point1 = action_data.roadpoints and #action_data.roadpoints > 0 and action_data.roadpoints[1].pose
					or action_data.roadpoints[1].tcp_pose
					or nil

				if false == welding_utils.arePointsSimilar(old_start_point, point1) then
					old_start_point = point1
					local point2 = action_data.roadpoints
							and #action_data.roadpoints > 1
							and action_data.roadpoints[2].pose
						or action_data.roadpoints[2].tcp_pose
						or nil
					local point3 = action_data.roadpoints
							and #action_data.roadpoints > 2
							and action_data.roadpoints[3].pose
						or action_data.roadpoints[3].tcp_pose
						or nil
					local start_rownum = action_data.index
					local end_rownum = action_data.index

					if point1 and point2 and point3 then
						table.insert(
							src_segs,
							welding_helpers.createSegment(
								false,
								point1,
								point2,
								point3,
								start_rownum,
								end_rownum,
								{},
								{},
								{}
							)
						)
					else
						log_error(welding_common.log_prefix .. "Missing roadpoints for event 2 processing")
					end
				end
			end
			::continue_inner::
		end

		if not has_end_air_move and last_weld_end_pose then
			local motion = channel_parameter.craft_param.motion
			local lift = tonumber(params.offset_distance) or 0
			if lift > 0 then
				local lifted_end_pose = poseTrans(last_weld_end_pose, { 0, 0, -lift, 0, 0, 0 })
				local resume_state, execute_motion = welding_resume.resolveResumeExecutionState()
				welding_motion.generateMoveLine(
					lifted_end_pose,
					params.motion_parameters.tool_speed,
					params,
					state,
					false,
					motion.weld_type,
					true,
					execute_motion
				)
				welding_arc.syncProgramPoint()
			end
		end
		::continue::
	end
end

return M
