local M = {}

-- 导入必要的模块
local sched = sched or require("aubo").sched
local welding_common = require("welding_common")
local welding_communication = require("welding_communication")
local welding_config = require("welding_config")
local welding_utils = require("welding_utils")
local welding_math = require("welding_math")

-- 起弧状态标志
local is_arcing_ = false
local arc_status_listeners_ = {}
local last_arc_stop_failed_ = false

-- 起弧统计
local realtime = require("aubo.realtime")
local arc_start_time = nil
local grouped_recording_enabled_ = false
local grouped_start_time_ = nil
local grouped_record_committed_ = false

local function safeKillThread(th, name)
	if th == nil then
		return
	end
	local ok, err = pcall(function()
		sched.kill(th)
	end)
	if not ok then
		log_warn(welding_common.log_prefix .. "safeKillThread failed: " .. tostring(name) .. ", err=" .. tostring(err))
	end
end

local function isLabelCommentEmpty(label)
	if type(label) ~= "table" then
		return true
	end
	local idx = label.point_index
	return idx == nil or idx == ""
end

-- ==================== 电弧控制 ====================

local function recordData(duration)
	local _ENV = sched.select_robot(1)

	log_info(welding_common.log_prefix .. "Begin recordData...")
	-- ---------- 距离统计 ----------
	local welding_motion = require("welding_motion")
	if welding_motion then
		local arcing_q = welding_motion.getArcingMotionQueue()
		local motion_q = welding_motion.getMotionQueue()

		if arcing_q and #arcing_q > 0 and motion_q then
			-- 建立 point_index -> motion 映射
			local motion_map = {}
			for _, m in ipairs(motion_q) do
				if m.point_index then
					motion_map[m.point_index] = m
				end
			end

			-- weld_type：取第一个点对应的
			local weld_type = nil
			local first = arcing_q[1]
			if first then
				local m = motion_map[first.point_index]
				if m then
					weld_type = m.weld_type
				end
			end

			if weld_type ~= nil then
				-- 获取 last_done
				local label = welding_utils.getAuboLabelComment()
				if isLabelCommentEmpty(label) then
					local welding = require("welding")
					local cached_label = welding.getCachedAuboLabelComment and welding.getCachedAuboLabelComment()
						or nil
					if not isLabelCommentEmpty(cached_label) then
						label = cached_label
						log_info(
							welding_common.log_prefix
								.. "use cached label comment in recordData, point_index="
								.. tostring(label.point_index)
						)
					else
						log_warn(
							welding_common.log_prefix
								.. "label comment empty and no cached label available in recordData"
						)
					end
				end
				local last_done = label and label.point_index
				if last_done and last_done > 0 then
					local dist_sum = 0
					local last_valid_motion = nil
					local last_valid_pose = nil

					-- 只累加 <= last_done
					for _, a in ipairs(arcing_q) do
						local idx = a.point_index
						if last_done and idx and idx <= last_done then
							local m = motion_map[idx]
							if m then
								if m.distance_to_prev then
									dist_sum = dist_sum + m.distance_to_prev
								end

								last_valid_motion = m
							end
						end
					end
					if last_valid_motion == nil and first then
						last_valid_motion = motion_map[last_done - 1]
					end

					-- 异常停止补偿 last_done → stop
					local welding = require("welding")
					if not welding.getProgramNormalStopState() and last_valid_motion then
						local stop_pose = getTcpPose()
						log_info(
							welding_common.log_prefix
								.. "getStopTcpPose: "
								.. welding_motion.formatPoseString(stop_pose)
						)
						local last_pose = last_valid_motion.poses[#last_valid_motion.poses]
						if last_pose and stop_pose then
							local next_motion = motion_map[last_done and (last_done + 1) or nil]

							local extra = 0

							if next_motion and next_motion.motion_type == welding_motion.MoveMode.MoveC then
								if next_motion.poses and next_motion.poses[2] then
									extra = welding_math.arcLengthPartial(
										last_pose,
										next_motion.poses[1],
										next_motion.poses[2],
										stop_pose
									)
								else
									extra = welding_math.distance(last_pose, stop_pose)
								end
							else
								extra = welding_math.distance(last_pose, stop_pose)
							end

							dist_sum = dist_sum + extra
						end
					end

					local records = {
						{
							weld_type = weld_type,
							weld_count = 1,
							weld_time = math.floor(duration + 0.5),
							weld_length = dist_sum,
						},
					}
					local res, err =
						welding_communication.getFunctionResult("WeldingStatistics.addWeldingRecord", { records })
					if not res then
						log_error(
							welding_common.log_prefix .. "WeldingStatistics.addWeldingRecord failed: " .. tostring(err)
						)
					end

					log_info(
						welding_common.log_prefix
							.. string.format(
								"Arc summary -> type: %s, distance: %.3f m, duration: %s",
								tostring(weld_type),
								tostring(dist_sum),
								tostring(duration)
							)
					)
				else
					log_error(welding_common.log_prefix .. "Failed to getLastPointIndex")
				end
			else
				log_error(welding_common.log_prefix .. "Arc summary skipped: missing weld_type")
			end
		else
			log_error(welding_common.log_prefix .. "Arc summary skipped: empty arc data")
		end
	else
		log_error(welding_common.log_prefix .. "Failed to require welding_motion for distance calc")
	end

	log_info(welding_common.log_prefix .. "End recordData...")
end

local function syncProgramPoint()
	local _ENV = sched.select_robot(1)
	log_info(welding_common.log_prefix .. "Sched.sync_program_point()")
	sched.sync_program_point()
end

local function setArcStatus(status)
	if status == is_arcing_ then
		return
	end
	is_arcing_ = status
	if status then
		log_info(welding_common.log_prefix .. "Arc Status Changed: true")
	else
		log_info(welding_common.log_prefix .. "Arc Status Changed: false")
	end

	if status then
		-- ================= 起弧 =================
		arc_start_time = realtime.time()
	else
		-- ================= 熄弧 =================
		local stop_time = realtime.time()

		-- ---------- 时间统计 ----------
		local duration = 0
		if arc_start_time then
			duration = stop_time - arc_start_time
		end
		arc_start_time = nil
		if grouped_recording_enabled_ then
		-- 分组统计由 endGroupedRecord 统一按分组起止时间计算
		else
			recordData(duration)
			local welding_motion = require("welding_motion")
			welding_motion.clearArcingMotionQueue()
		end
	end

	-- ================= 回调通知 =================
	for _, cb in ipairs(arc_status_listeners_) do
		local ok, err = pcall(cb, is_arcing_)
		if not ok then
			log_error("ArcStatusChanged callback error: " .. tostring(err))
		end
	end
end

local function beginGroupedRecord()
	grouped_recording_enabled_ = true
	grouped_start_time_ = realtime.time()
	grouped_record_committed_ = false
end

local function endGroupedRecord()
	if grouped_record_committed_ then
		return
	end

	if not grouped_recording_enabled_ then
		return
	end

	grouped_recording_enabled_ = false
	local total_duration = 0
	if grouped_start_time_ then
		local now = realtime.time()
		total_duration = math.max(0, now - grouped_start_time_)
	end

	recordData(total_duration)
	grouped_start_time_ = nil
	grouped_record_committed_ = true

	local welding_motion = require("welding_motion")
	welding_motion.clearArcingMotionQueue()
end

local function arcStatusChanged(cb)
	if type(cb) ~= "function" then
		return
	end
	table.insert(arc_status_listeners_, cb)
end

local function isArcing()
	return is_arcing_
end

local function isGroupedRecording()
	return grouped_recording_enabled_ == true
end

-- 起弧
local function startArc()
	-- 防止重复起弧：已处于起弧状态时直接返回，避免重复启动检测/调参线程
	if isArcing() then
		log_warn(welding_common.log_prefix .. "startArc skipped: already arcing")
		return
	end

	log_info(welding_common.log_prefix .. "startArc")

	local _ENV = sched.select_robot(1)
	syncProgramPoint()

	last_arc_stop_failed_ = false
	if welding_config.setArcLostDetected then
		welding_config.setArcLostDetected(false)
	end

	local arcing_successed = false
	local initial_time = 0

	-- 打开送气
	welding_config.setGasSolenoidState(true)
	sched.sleep(welding_config.getDeliveryTime())

	-- 输出起弧电流电压
	welding_config.setTargetCurrentOutput(welding_config.getStartArcCurrent())
	log_info(welding_common.log_prefix .. "setTargetCurrentOutput:" .. welding_config.getStartArcCurrent())
	welding_config.setTargetVoltageOutput(welding_config.getStartArcVoltage())
	log_info(welding_common.log_prefix .. "setTargetVoltageOutput:" .. welding_config.getStartArcVoltage())

	if not welding_config.getArcIoOutput() then
		local count = 0
		-- 起弧最多重试 3 次
		while count < 3 do
			count = count + 1
			if arcing_successed == false then
				welding_config.setArcIoOutput(false)
				sched.sleep(0.2)
				welding_config.setArcIoOutput(true)
				initial_time = 0
				-- 每次起弧最多等 1 秒
				while initial_time < 1 do
					if welding_config.getArcIoOutput() then
						log_info(welding_common.log_prefix .. "Start arcing")
						arcing_successed = true
						break
					else
						initial_time = initial_time + sched.sync_time
						sched.sync()
					end
				end
				if arcing_successed == true then
					break
				end
				welding_config.setArcIoOutput(false)
			end
		end
		-- 未起弧成功，重置模拟输出并且停止程序提示报错信息
		if arcing_successed == false then
			welding_config.setGasSolenoidState(false)
			welding_config.setTargetCurrentOutput(0)
			welding_config.setTargetVoltageOutput(0)
			welding_config.setArcIoOutput(false)
			sched.sleep(0.2)
			log_error(welding_common.log_prefix .. "Arc initiation failed")
			welding_common.showErrorMessage(welding_common.ERROR_ENUM.ARC_INITIATION_FAILED)
			abort()
		end
	else
		-- 即使对方给了起弧成功信号，也下发一下起弧信号，对方可能是误给
		welding_config.setArcIoOutput(true)
	end

	setArcStatus(true)
	-- 开启检测断弧监控
	sched.run(welding_config.detection_arcing_thread)

	-- 等待起弧时间
	sched.sleep(welding_config.getStartArcWaitTime())
	-- 输出焊接电流电压
	welding_config.setTargetCurrentOutput(welding_config.getCurrent())
	log_info(welding_common.log_prefix .. "setTargetCurrentOutput:" .. welding_config.getCurrent())
	welding_config.setTargetVoltageOutput(welding_config.getVoltage())
	log_info(welding_common.log_prefix .. "setTargetVoltageOutput:" .. welding_config.getVoltage())
end

-- 熄弧
local function stopArc(is_emergency)
	log_info(welding_common.log_prefix .. "stopArc")
	local _ENV = sched.select_robot(1)
	last_arc_stop_failed_ = false

	if is_emergency == nil then
		is_emergency = false
	end

	if is_emergency then
		-- 异常熄弧，立即停止
		welding_config.setArcIoOutput(false)
		welding_config.setGasSolenoidState(false)

		safeKillThread(welding_config.detection_arcing_thread, "detection_arcing_thread")
	else
		-- 正常熄弧，等待运行结束
		syncProgramPoint()
		-- 输出熄弧电流电压
		welding_config.setTargetCurrentOutput(welding_config.getStopArcCurrent())
		log_info(welding_common.log_prefix .. "setTargetCurrentOutput:" .. welding_config.getStopArcCurrent())
		welding_config.setTargetVoltageOutput(welding_config.getStopArcVoltage())
		log_info(welding_common.log_prefix .. "setTargetVoltageOutput:" .. welding_config.getStopArcVoltage())
		-- 等待熄弧时间
		sched.sleep(welding_config.getStopArcWaitTime())
		-- 最后熄弧
		welding_config.setArcIoOutput(false)
		log_info(welding_common.log_prefix .. "Start arc blowout")

		local t = 0
		local interval = 0.1 -- 100ms
		local timeout = 3.0 -- 3秒超时
		local stop_arc_successed = false
		while t < timeout do
			if not welding_config.getArcIoOutput() then
				stop_arc_successed = true
				break
			end
			sched.sleep(interval)
			t = t + interval
		end

		safeKillThread(welding_config.detection_arcing_thread, "detection_arcing_thread")

		if not stop_arc_successed then
			last_arc_stop_failed_ = true

			welding_config.setGasSolenoidState(false)
			welding_config.setTargetCurrentOutput(0)
			welding_config.setTargetVoltageOutput(0)
			log_error(welding_common.log_prefix .. "Arc extinguishing failed")
			welding_common.showErrorMessage(welding_common.ERROR_ENUM.ARC_STOP_FAILED)
			abort()
		end

		-- 重新打开送气
		welding_config.setGasSolenoidState(true)
		log_info(welding_common.log_prefix .. "setGasSolenoidState:true")
		sched.sleep(welding_config.getDeliveryTime())
		welding_config.setGasSolenoidState(false)
		log_info(welding_common.log_prefix .. "setGasSolenoidState:false")
	end

	-- 熄弧成功，重置模拟输出
	welding_config.setTargetCurrentOutput(0)
	log_info(welding_common.log_prefix .. "setTargetCurrentOutput:0")
	welding_config.setTargetVoltageOutput(0)
	log_info(welding_common.log_prefix .. "setTargetVoltageOutput:0")

	setArcStatus(false)
	if is_emergency then
		endGroupedRecord()
	end
end

local function isLastArcStopFailed()
	return last_arc_stop_failed_ == true
end

-- 导出模块
M.syncProgramPoint = syncProgramPoint
M.isArcing = isArcing
M.isGroupedRecording = isGroupedRecording
M.startArc = startArc
M.stopArc = stopArc
M.isLastArcStopFailed = isLastArcStopFailed
M.arcStatusChanged = arcStatusChanged
M.beginGroupedRecord = beginGroupedRecord
M.endGroupedRecord = endGroupedRecord

return M
