local Logger = {}

-- 全局的print,必须使用封装的Logger
if not EDITOR_MODE then
    print = function(...)
        Logger.log(...)
    end
end

Logger.tab = "    "
Logger.MANUAL_ENABLE_DEBUG = false -- 手动控制激活打印
Logger.ENABLE_TIMES = 5 -- 激活需要的操作次数

local function split(input, delimiter)
    input = tostring(input)
    delimiter = tostring(delimiter)
    if (delimiter=='') then return false end
    local pos,arr = 0, {}
    -- for each divider found
    for st,sp in function() return string.find(input, delimiter, pos, true) end do
        table.insert(arr, string.sub(input, pos, st - 1))
        pos = sp + 1
    end
    table.insert(arr, string.sub(input, pos))
    return arr
end

local formatTable
formatTable = function(tal, _depth)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    if type(tal) ~= "table" then
        return tostring(tal)
    else
        local _depth = _depth or 0
        local getTab = function()
            local r = ""
            for _ = 1, _depth do
                r = r.. Logger.tab
            end
            return r
        end
        local result = "{\n"
        _depth = _depth + 1
        for k, v in pairs(tal) do
            if type(v) ~= "table" then
                result = result.. getTab().. tostring(k).. " = ".. tostring(v).. "\n"
            else
                result = result.. getTab().. tostring(k).. " = ".. formatTable(v, _depth + 1) .. "\n"
            end
        end
        result = result.. getTab()..  "}"
        return result
    end
end

Logger.printTable = function(tbl)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger.log(formatTable(tbl))
end

Logger.printTableWarning = function(tbl)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger.logWarning(formatTable(tbl))
end

Logger.printTableError = function(tbl)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger.logError(formatTable(tbl))
end

Logger.log = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger._log("INFO", fmt, ...)
end

Logger.logTodo = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    local t = { string.format(tostring(fmt), ...), }
    local traceback = split(debug.traceback("", 2), "\n")
    CS.UnityEngine.Debug.Log("<color=magenta>[TODO] " .. table.concat(t) .. "</color>" .. table.concat(traceback, "\n"))
end

Logger.logHighlight = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    local t = { string.format(tostring(fmt), ...), }
    local traceback = split(debug.traceback("", 2), "\n")
    CS.UnityEngine.Debug.Log("<color=yellow>" .. table.concat(t) .. "</color>" .. table.concat(traceback, "\n"))
end

Logger.logWarning = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger._log("WARNING", fmt, ...)
end

Logger.logError = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger._log("ERROR", fmt, ...)
end

Logger.logFatal = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    Logger._log("FATAL", fmt, ...)
end

Logger.logWarningBox = function(fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end

    local content = Logger._log("WARNING", fmt, ...)
    local params = {
        content = content,
        okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
        noShowClose = true,
        okFunc = function() end,
        boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
        top = true,
    }
    GFunc.showMessageBox(params)
end

Logger._log = function(tag, fmt, ...)
    if IS_PUBLISH and not Logger.MANUAL_ENABLE_DEBUG then
        return
    end
    local str = Logger._checkPercentSign(fmt)
    local t = { string.format(tostring(str), ...), }
    local traceback = split(debug.traceback("", 2), "\n")
    local output
    if tag == "FATAL" then
        output = table.concat(t) ..table.concat(traceback, "\n")
        CS.UnityEngine.Debug.LogError(output)
    elseif tag == "ERROR" then
        CS.UnityEngine.Debug.Log("<color=red>" .. table.concat(t) .. "</color>" .. table.concat(traceback, "\n"))
    elseif tag == "WARNING" then
        output = table.concat(t) ..table.concat(traceback, "\n")
        CS.UnityEngine.Debug.LogWarning(output)
    else
        output = table.concat(t) ..table.concat(traceback, "\n")
        CS.UnityEngine.Debug.Log(output)
    end

    return output
end

local function dump_value_(v)
    if type(v) == "string" then
        v = "\"" .. v .. "\""
    end
    return tostring(v)
end

Logger.dump = function(value, description, nesting)
    if IS_PUBLISH then
        return
    end
    if type(nesting) ~= "number" then nesting = 3 end

    local lookupTable = {}
    local result = {}

    local traceback = split(debug.traceback("", 2), "\n")
    CS.UnityEngine.Debug.Log("dump from: " .. string.trim(traceback[3]))

    local function dump_(value, description, indent, nest, keylen)
        description = description or "<var>"
        local spc = ""
        if type(keylen) == "number" then
            spc = string.rep(" ", keylen - string.len(dump_value_(description)))
        end
        if type(value) ~= "table" then
            result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(description), spc, dump_value_(value))
        elseif lookupTable[tostring(value)] then
            result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(description), spc)
        else
            lookupTable[tostring(value)] = true
            if nest > nesting then
                result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(description))
            else
                result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(description))
                local indent2 = indent.."    "
                local keys = {}
                local keylen = 0
                local values = {}
                for k, v in pairs(value) do
                    keys[#keys + 1] = k
                    local vk = dump_value_(k)
                    local vkl = string.len(vk)
                    if vkl > keylen then keylen = vkl end
                    values[k] = v
                end
                table.sort(keys, function(a, b)
                    if type(a) == "number" and type(b) == "number" then
                        return a < b
                    else
                        return tostring(a) < tostring(b)
                    end
                end)
                for i, k in ipairs(keys) do
                    dump_(values[k], k, indent2, nest + 1, keylen)
                end
                result[#result +1] = string.format("%s}", indent)
            end
        end
    end
    dump_(value, description, "- ", 1)

    for i, line in ipairs(result) do
        CS.UnityEngine.Debug.Log(line)
    end
end

Logger._checkPercentSign = function (str)
    if str == nil then
        return nil
    end
    str = tostring(str)
	local strTable = {}
	for i = 1, #str do
		table.insert(strTable, str:sub(i,i))
	end
	local count = #strTable
	local specialChars = {"s","p","c","w","a","l","u","d","x","z",}
	for i = count, 1, -1 do
		if strTable[i] == '%' and (i + 1) <= count then
			local pattern = false
			for _, char in ipairs(specialChars) do
				if strTable[i + 1] == char then
					pattern = true
					break
				end
			end
			if not pattern then
				table.insert(strTable, i + 1, "%")
			end
		elseif strTable[i] == '%' and i == count then
			table.insert(strTable, "%")
		end
	end
	return table.concat(strTable)
end

return Logger
