local type, tostring, unpack, select = type, tostring, unpack, select
local string_format = string.format
local table_concat = table.concat
local decoda_output = decoda_output
local setmetatable = setmetatable
local core = require "lualiblogger.core"

module((...))

_M.dest = core.dest
_M.level = core.level
_M.options = core.options

local function LogArgumentsFormatter(...)
	local args = {...}
	for i=1, select("#", ...) do
		local arg = args[i]
		local arg_type = type(arg)
		if arg_type ~= "string" and arg_type ~= "number" then
			args[i] = tostring(arg)
		end
	end
	return unpack(args)
end

local function ArgumentsToStrings(t, ...)
	for i=1, select("#", ...)  do
		local arg = select(i, ...)
		local arg_type = type(arg)
		if arg_type ~= "string" and arg_type ~= "number" then
			t[#t + 1] = tostring(arg)
		else
			t[#t + 1] = arg
		end
	end
	return t
end

local function BuildMessage(fmt, ...)
	local msg
	if type(fmt) ~= "string" then
		msg = { tostring(fmt) }
		ArgumentsToStrings(msg, ...)
		msg = table_concat(msg, "\t")
	else
		if fmt:find("%%") then
			msg = string_format(fmt, LogArgumentsFormatter(...))
		else
			msg = { fmt }
			ArgumentsToStrings(msg, ...)
			msg = table_concat(msg, "\t")
		end
	end
	return msg
end

local function MakeLogger(logger)
	local t = {}
	t.Debug = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogDebug(logger, msg)
		if decoda_output then decoda_output("[DEBUG] " .. msg) end
		return msg
	end

	t.Info = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogInfo(logger, msg)
		if decoda_output then decoda_output("[INFO ] " .. msg) end
		return msg
	end
	
	t.Warning = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogWarning(logger, msg)
		if decoda_output then decoda_output("[WARN ] " .. msg) end
		return msg
	end
	
	t.Error = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogError(logger, msg)
		if decoda_output then decoda_output("[ERROR] " .. msg) end
		return msg
	end
	
	t.Fatal = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogFatal(logger, msg)
		if decoda_output then decoda_output("[FATAL] " .. msg) end
		return msg
	end
	
	t.Profile = function(fmt, ...)
		local msg = BuildMessage(fmt, ...)
		core.LogProfile(logger, msg)
		if decoda_output then decoda_output("[PROFILER] " .. msg) end
		return msg
	end
	
	t.__tostring = function()
		return tostring(logger)
	end
	
	t.log = t.Debug
	t.debug = t.Debug
	t.info = t.Info
	t.warn = t.Warning
	t.error = t.Error
	t.fatal = t.Fatal
	t.profile = t.Profile

	setmetatable(t, t)
	return t
end


function new(appName)
	local logger = core.new(appName)
	return MakeLogger(logger)
end

function custom(appName, level, destination, options, async)
	local logger = core.custom(appName, level, destination, options, async)
	return MakeLogger(logger)
end