local W={}local f="\040\091\095\037\119\093\043\058\037\100\043\041"local e=4 local R={ERROR={Name="\069\082\082\079\082",Enabled=true,Tag="\226\157\140"},WARN={Name="\087\065\082\078";Enabled=true;Tag="\226\154\160\239\184\143"},INFO={Name="\073\078\070\079",Enabled=true,Tag="\240\159\148\185"},TRACE={Name="\084\082\065\067\069",Enabled=false;Tag="\240\159\147\140"}}W.Level=R local function r()local W=(debug.traceback()):split("\n")if W and#W>=e then local R=W[e]if R then for W in R:gmatch(f)do return W end end end return"\085\110\107\110\111\119\110 \083\111\117\114\099\101"end local function N(...)local W={}for f,e in pairs({...})do table.insert(W,tostring(e))end return table.concat(W," ")end local function o(W,...)return("\240\159\148\140 \037\115 \124\037\115\124 \037\115"):format(W.Tag,r(),N(...))end function W.MacroInfo(e,f,...)if not W.Level.INFO.Enabled then return end local R=f.Icon and(not string.find(f.Icon,"\114\098\120\097\115\115\101\116")and f.Icon)or""print(("\091\037\115 \037\115\093"):format(R,f.Name),...)end function W.MacroWarn(e,f,...)if not W.Level.WARN.Enabled then return end local R=f.Icon and(not string.find(f.Icon,"\114\098\120\097\115\115\101\116")and f.Icon)or""warn(("\091\037\115 \037\115\093"):format(R,f.Name),...)end function W.Trace(f,...)if not W.Level.TRACE.Enabled then return end print(o(W.Level.TRACE),...)end function W.Info(f,...)if not W.Level.INFO.Enabled then return end print(o(W.Level.INFO),...)end function W.Warn(f,...)if not W.Level.WARN.Enabled then return end warn(o(W.Level.WARN),...)end function W.Error(f,...)if not W.Level.ERROR.Enabled then return end error(o(W.Level.ERROR,...),e)end return W
---
---Functions to nicely log things to the console under the umbrella of Socket
---
---@class Logger
---
local Logger = {}

--------------------------------------------------
-- Dependencies
-- ...

--------------------------------------------------
-- Types

---@class LoggerLevel
---@field Name string
---@field Enabled boolean
---@field Tag string

--------------------------------------------------
-- Constants

---
---Pattern that extracts the script's name and the current line from a stacktrace.
---
--- - [_%w]+ = Represents all alphanumeric characters, plus underscores. This captures the script's name.
--- - %d+ = Represents all digits. This captures the line of code being executed.
---
---Line where the source can be found in tracebacks.
---
---More information at https://www.lua.org/manual/5.3/manual.html#6.4.1
---
local TRACEBACK_PATTERN = "([_%w]+:%d+)"
local TRACEBACK_SOURCE_LINE = 4

local LEVEL = {
    ERROR = {
        Name = "ERROR",
        Enabled = true,
        Tag = "❌",
    },
    WARN = {
        Name = "WARN",
        Enabled = true,
        Tag = "⚠️",
    },
    INFO = {
        Name = "INFO",
        Enabled = true,
        Tag = "🔹",
    },
    TRACE = {
        Name = "TRACE",
        Enabled = false,
        Tag = "📌",
    },
} ---@type table<string, LoggerLevel>
Logger.Level = LEVEL

--------------------------------------------------
-- Members

---
---Returns the name of the source being executed and its line of code as well.
---@return string
---
local function getSourceName()
    local tracebackLines = debug.traceback():split("\n")
    if tracebackLines and #tracebackLines >= TRACEBACK_SOURCE_LINE then
        local sourceLine = tracebackLines[TRACEBACK_SOURCE_LINE]
        if sourceLine then
            for trace in sourceLine:gmatch(TRACEBACK_PATTERN) do
                return trace
            end
        end
    end
    return "Unknown Source"
end

---
---Concatenates variables into a string. All vararg values are parsed as string before being concatenated.
---
---@return string
---
local function concatVars(...)
    -- Convert to strings
    local stringVars = {}
    for _, var in pairs({ ... }) do
        table.insert(stringVars, tostring(var))
    end

    return table.concat(stringVars, " ")
end

---@param loggerLevel LoggerLevel
local function writeSourceOutput(loggerLevel, ...)
    return ("🔌 %s |%s| %s"):format(loggerLevel.Tag, getSourceName(), concatVars(...))
end

---
---[] A macro wants to show console information
---
---@param macro MacroDefinition
---@vararg any
---
function Logger:MacroInfo(macro, ...)
    -- RETURN: Disabled
    if not Logger.Level.INFO.Enabled then
        return
    end

    local icon = macro.Icon and not string.find(macro.Icon, "rbxasset") and macro.Icon or ""
    print(("[%s %s]"):format(icon, macro.Name), ...)
end

---
---[] A macro wants to warn
---
---@param macro MacroDefinition
---@vararg any
---
function Logger:MacroWarn(macro, ...)
    -- RETURN: Disabled
    if not Logger.Level.WARN.Enabled then
        return
    end

    local icon = macro.Icon and not string.find(macro.Icon, "rbxasset") and macro.Icon or ""
    warn(("[%s %s]"):format(icon, macro.Name), ...)
end

---
---📌 Core, detailed system information
---
---@vararg any
---
function Logger:Trace(...)
    -- RETURN: Disabled
    if not Logger.Level.TRACE.Enabled then
        return
    end

    print(writeSourceOutput(Logger.Level.TRACE), ...)
end

---
---🔹 Generic and useful information about system operation.
---
---@vararg any
---
function Logger:Info(...)
    -- RETURN: Disabled
    if not Logger.Level.INFO.Enabled then
        return
    end

    print(writeSourceOutput(Logger.Level.INFO), ...)
end

---
---🚧 Warnings, poor usage of the API, or 'almost' errors.
---
---@vararg any
---
function Logger:Warn(...)
    -- RETURN: Disabled
    if not Logger.Level.WARN.Enabled then
        return
    end

    warn(writeSourceOutput(Logger.Level.WARN), ...)
end

---
---❌ Severe runtime errors or unexpected conditions.
---
---@vararg any
---
function Logger:Error(...)
    -- RETURN: Disabled
    if not Logger.Level.ERROR.Enabled then
        return
    end

    error(writeSourceOutput(Logger.Level.ERROR, ...), TRACEBACK_SOURCE_LINE)
end

return Logger
