local M = {}
M.language = "en"

-- 导入必要的模块
local sched = sched or require("aubo").sched
local halt = sched.halt

local main_tid = nil
local log_prefix = "[Welding] "
local raw_log_info = log_info
local raw_log_error = log_error
local raw_log_warn = log_warn
local arcs_ws_path = os.getenv("ARCS_WS")
if not arcs_ws_path or arcs_ws_path == "" then
	arcs_ws_path = (os.getenv("HOME") or "/root") .. "/arcs_ws"
end
local lua_log_dirs = {
	arcs_ws_path .. "/log/welding",
	"/root/arcs_ws/log/welding",
}
local active_lua_log_path

local function ensureDir(path)
	if type(os.execute) ~= "function" then
		return nil, "os.execute unavailable"
	end
	local ok = os.execute(string.format('mkdir -p "%s"', path))
	if ok == true or ok == 0 then
		return true
	end
	return nil, "failed to create directory: " .. tostring(path)
end

local function stringifyLogArgs(...)
	local count = select("#", ...)
	local parts = {}
	for i = 1, count do
		parts[i] = tostring(select(i, ...))
	end
	return table.concat(parts, " ")
end

local function formatLuaLogLine(message)
	local timestamp = os.date("%Y-%m-%d %H:%M:%S")
	if not timestamp then
		return message
	end
	return string.format("[%s] %s", timestamp, message)
end

local function resolveLuaLogPath(reset_file)
	if active_lua_log_path and not reset_file then
		return active_lua_log_path
	end

	local tried = {}
	for _, dir in ipairs(lua_log_dirs) do
		local ensured = false
		local ok = ensureDir(dir)
		if ok then
			ensured = true
		end

		local path = dir .. "/welding_lua.log"
		local mode = reset_file and "w" or "a"
		local f = io.open(path, mode)
		if f then
			f:close()
			active_lua_log_path = path
			return active_lua_log_path
		end

		if not ensured then
			tried[#tried + 1] = path .. " (mkdir unavailable or failed)"
		else
			tried[#tried + 1] = path
		end
	end

	return nil, "no writable log path: " .. table.concat(tried, ", ")
end

local function appendLuaLogLine(message)
	local lua_log_path, path_err = resolveLuaLogPath(false)
	if not lua_log_path then
		return nil, path_err
	end

	local f, open_err = io.open(lua_log_path, "a")
	if not f then
		active_lua_log_path = nil
		return nil, open_err
	end

	local log_line = formatLuaLogLine(message)
	local write_ok, write_err = pcall(f.write, f, log_line .. "\n")
	f:close()
	if not write_ok then
		return nil, write_err
	end

	return true
end

local function resetLuaLogFile()
	active_lua_log_path = nil
	local lua_log_path, open_err = resolveLuaLogPath(true)
	if not lua_log_path then
		if raw_log_info then
			raw_log_info(log_prefix .. " Failed to reset Lua log file: " .. tostring(open_err))
		end
		return
	end
end

local function mirrorAnyLog(level, tag, ...)
	local message = stringifyLogArgs(...)
	if message == "" then
		return
	end
	local ok, err = appendLuaLogLine(string.format("[%s] %s%s", tostring(level or "INFO"), tag or "", message))
	if not ok and raw_log_info then
		raw_log_info(log_prefix .. " Failed to mirror Lua log: " .. tostring(err))
	end
end

local function mirroredLogInfo(...)
	if raw_log_info then
		raw_log_info(...)
	end
	mirrorAnyLog("INFO", "", ...)
end

local function mirroredLogError(...)
	if raw_log_error then
		raw_log_error(...)
	end
	mirrorAnyLog("ERROR", "", ...)
end

local function mirroredLogWarn(...)
	if raw_log_warn then
		raw_log_warn(...)
	end
	mirrorAnyLog("WARN", "", ...)
end

resetLuaLogFile()
log_info = mirroredLogInfo
log_error = mirroredLogError
log_warn = mirroredLogWarn
log_info(log_prefix .. " welding_common log mirror initialized: " .. tostring(active_lua_log_path or "unavailable"))

-- ====================== 错误码表 ======================
local ErrorCode = {
	-- 通用错误
	COMMON = {
		SUCCESS = 0,
		TABLE_ERROR = 998,
		UNKNOWN_ERROR = 999,
	},
	-- 路点相关错误
	WAYPOINT = {
		POSE_DIMENSION_MISMATCH = 1001, -- 位姿维度不对
		JOINT_DIMENSION_MISMATCH = 1002, -- 关节角维度对
		EMPTY_WAYPOINT = 1003, -- 路点为空（无有效路径点）
		DIMENSION_ERR_WAYPOINT = 1004, -- 路点维度错误
	},

	--摆动类型相关错误
	WEAVE = {
		TYPE_ERR = 2001, --类型错误
		AMPLITUDE_ERR = 2002, -- 振幅错误
		FREQUENCY_ERR = 2003, --频率错误
	},

	--线激光设备错误
	LINELASER = {
		CONNECTFAILED = 3001, --连接失败
		OPEN_LASER_ERR = 3002, -- 打开激光失败
		CLOSE_LASER_ERR = 3003, -- 关闭激光失败
		SET_TEMPLATE_ERR = 3004, -- 设置模板失败
	},

	--断续焊错误
	INTERMITTENT = {
		WELD_LEN_ERR = 4001, -- 焊接段长度错误
		NON_WELD_LEN_ERR = 4002, -- 空走段长度错误
		PARAM_VALUE_ERR = 4003, -- 参数值错误
		MODE_ERR = 4004, -- 模式错误
	},
}

local ERROR_ENUM = {
	ARC_INITIATION_FAILED = "Arc initiation failed",
	ARC_STOP_FAILED = "Arc extinguishing failed",
	POSE_DATA_EMPTY = "Pose data is empty or dimension mismatch (expected 6D)",
	OP_POINT_SETUP_FAILED = "Automatic setting of op point failed",
	REFERENCE_FRAME_FAILED = "Set refframe failed",
	HTTP_REQUEST_TIMEOUT = "Line laser HTTP request timed out (2s)",
	LINE_LASER_CONFIG_INVALID = "Line laser device configuration is invalid",
	LINE_LASER_TARGET_POSE_READ_FAILED = "Failed to read target pose from line laser",
	MULTIPLE_CHANNELS_EMPTY = "Multiple channels are empty",
	NO_WELD_SEAM = "Line laser did not identify a weld seam",
	MP_O_INVERSE_FAILED = "Inverse solution failed for mp_o_point",
	MP_P_INVERSE_FAILED = "Inverse solution failed for mp_p_point",
	WELDING_ARC_LOST = "During the welding process, it was detected that the welding machine lost its arc, and the program was stopped.",
	LASER_INVERSE_KINEMATICS_FAILED = "InverseKinematics failed for laser point",
	RUN_LINE_NUMBER = "Run line number",
	SWING_CALCULATION_ERROR = "Straight-tooth swing calculation error",
	INVERSE_SOLUTION_FAILED = "Inverse solution failed",
	ROLLBACK_DISTANCE_EXCEEDED = "Rollback distance exceeds traveled path",
}

local TRANSLATIONS = {
	zh_CN = {
		[ERROR_ENUM.ARC_INITIATION_FAILED] = "起弧失败",
		[ERROR_ENUM.ARC_STOP_FAILED] = "熄弧失败",
		[ERROR_ENUM.POSE_DATA_EMPTY] = "姿态数据为空或数据不匹配（预期为6维）",
		[ERROR_ENUM.OP_POINT_SETUP_FAILED] = "自动设置 op 点失败",
		[ERROR_ENUM.REFERENCE_FRAME_FAILED] = "设置参考坐标系失败",
		[ERROR_ENUM.HTTP_REQUEST_TIMEOUT] = "线激光HTTP请求响应超时（2秒）",
		[ERROR_ENUM.LINE_LASER_CONFIG_INVALID] = "线激光设备配置无效",
		[ERROR_ENUM.LINE_LASER_TARGET_POSE_READ_FAILED] = "读取线激光目标位姿失败",
		[ERROR_ENUM.MULTIPLE_CHANNELS_EMPTY] = "多道道数为空",
		[ERROR_ENUM.NO_WELD_SEAM] = "线激光未识别到焊缝",
		[ERROR_ENUM.MP_O_INVERSE_FAILED] = "O 点逆解计算失败",
		[ERROR_ENUM.MP_P_INVERSE_FAILED] = "P 点逆解计算失败",
		[ERROR_ENUM.WELDING_ARC_LOST] = "焊接过程中检测到焊机断弧，程序停止。",
		[ERROR_ENUM.LASER_INVERSE_KINEMATICS_FAILED] = "激光点的逆向运动学计算失败",
		[ERROR_ENUM.RUN_LINE_NUMBER] = "运行行号",
		[ERROR_ENUM.SWING_CALCULATION_ERROR] = "直线锯齿摆动计算错误",
		[ERROR_ENUM.INVERSE_SOLUTION_FAILED] = "逆解失败",
		[ERROR_ENUM.ROLLBACK_DISTANCE_EXCEEDED] = "回退距离超过当前已走路径长度",
	},
	en = {},
}

local function tr(error_enum)
	local dict = TRANSLATIONS[M.language]
	return dict and dict[error_enum] or error_enum
end

local function setMainThreadId(tid)
	if main_tid == nil then
		main_tid = tid
		log_info(log_prefix .. " set main_tid: " .. tostring(main_tid))
	end
end

local function getMainThreadId()
	return main_tid
end

local function showErrorMessage(error_enum)
	local _ENV = sched.select_robot(1)
	clearNamedVariable("_popup_continue_or_stop")
	do
		local _popup_t = getControlSystemTime()

		popup(TraceLevel.ERROR, "Error", tr(error_enum), 1)

		halt()
		while not variableUpdated("_popup_continue_or_stop", _popup_t) do
			sync()
		end
		if not getBool("_popup_continue_or_stop", true) then
			halt()
		end
	end
end

local function writeFile(filepath, content)
	local f, err = io.open(filepath, "w")
	if not f then
		return nil, err
	end
	local ok, write_err = pcall(f.write, f, content or "")
	f:close()
	if not ok then
		return nil, write_err
	end
	return true
end

-- 导出模块
M.log_prefix = log_prefix
M.arcs_ws_path = arcs_ws_path
M.ErrorCode = ErrorCode
M.ERROR_ENUM = ERROR_ENUM
M.TRANSLATIONS = TRANSLATIONS
M.tr = tr
M.setMainThreadId = setMainThreadId
M.getMainThreadId = getMainThreadId
M.showErrorMessage = showErrorMessage
M.writeFile = writeFile

return M
