local L = LibStub("AceLocale-3.0"):GetLocale("CritMatic")
local MESSAGE_SPACING = 3

local activeMessages = {}
--/run CritMatic.ShowNewCritMessage("Killing Spree", 300)CritMatic.ShowNewNormalMessage("Killing Spree",435)

-- Utility function to convert percentage to pixel offset
local function ConvertPercentageToOffset(xPercent, yPercent)
    local screenWidth = UIParent:GetWidth()
    local screenHeight = UIParent:GetHeight()
    
    -- Convert percentages to pixel offsets from center
    local xOffset = (xPercent - 50) * screenWidth / 100
    local yOffset = (yPercent - 50) * screenHeight / 100
    
    return xOffset, yOffset
end

-- Utility function to adjust message positions
local function AdjustMessagePositions()
    -- Get position settings from database
    local xPos = Critmatic.db.profile.alertNotificationFormat.position.xPos
    local yPos = Critmatic.db.profile.alertNotificationFormat.position.yPos
    
    -- Convert percentages to pixel offsets
    local xOffset, yOffset = ConvertPercentageToOffset(xPos, yPos)
    
    -- Position the first message using configurable values
    activeMessages[1]:SetPoint("CENTER", UIParent, "CENTER", xOffset, yOffset)

    -- Position subsequent messages relative to the previous one
    for i = 2, #activeMessages do
        activeMessages[i]:SetPoint("TOP", activeMessages[i - 1], "BOTTOM", 0, -MESSAGE_SPACING)
    end
end




-- Utility function to remove the oldest message and adjust the rest
local function RemoveOldestMessage()
    local oldestMessage = table.remove(activeMessages)  -- Remove the oldest message (first in the table)

    -- Hide the message frame and perform any necessary cleanup
    if oldestMessage then
        oldestMessage:Hide()

    end
end

Critmatic.MessageFrame = {}

function Critmatic.FormatPreviousRecord(oldAmount, newAmount)
    if not Critmatic.db.profile.generalSettings.showPreviousRecord then
        return ""
    end
    if not oldAmount or oldAmount <= 0 or not newAmount then
        return ""
    end
    return string.format("previous %d", oldAmount)
end

local ICON_SIZE = 24
local ICON_SPACING = 6

local function cloneTextStyle(f, justify)
    local fs = f:CreateFontString(nil, "ARTWORK")
    local fontPath, fontSize, fontFlags = f.text:GetFont()
    if fontPath then fs:SetFont(fontPath, fontSize, fontFlags) end
    fs:SetTextColor(f.text:GetTextColor())
    local sx, sy = f.text:GetShadowOffset()
    if sx then fs:SetShadowOffset(sx, sy) end
    fs:SetShadowColor(f.text:GetShadowColor())
    if fs.SetWordWrap then fs:SetWordWrap(false) end
    fs:SetJustifyH(justify or "LEFT")
    return fs
end

local function attachCountUpFS(f, fs, lineText, amount, yOffset)
    local countUpLib = LibStub("LibMatic-CountUp-1.0", true)
    if not countUpLib then return nil end
    if type(amount) ~= "number" or amount <= 0 then return nil end

    local countUpDuration = Critmatic.db.profile.alertNotificationFormat.global.countUpDuration or 3
    local numStr = tostring(math.floor(amount + 0.5))
    local nStart, nEnd = string.find(lineText, numStr, 1, true)
    if not nStart then return nil end

    local prefix = string.sub(lineText, 1, nStart - 1)
    local suffix = string.sub(lineText, nEnd + 1)

    local centerOffsetX = 0
    if f.icon and f.icon:IsShown() then
        centerOffsetX = (ICON_SIZE + ICON_SPACING) / 2
    end

    fs:SetText(lineText)
    local finalWidth = fs:GetStringWidth() or 0
    if finalWidth > 0 then
        fs:ClearAllPoints()
        fs:SetPoint("LEFT", f, "CENTER", centerOffsetX - finalWidth / 2, yOffset or 0)
        fs:SetWidth(finalWidth + math.max(8, #numStr * 4))
        fs:SetJustifyH("LEFT")
        if fs.SetWordWrap then fs:SetWordWrap(false) end
    end

    local counter = countUpLib:Attach(fs, {
        duration = countUpDuration,
        easing = "linear",
        minValue = 0,
        formatter = function(v)
            return prefix .. tostring(math.floor(v + 0.5)) .. suffix
        end,
    })
    counter:Set(0)
    counter:To(amount)
    return counter
end

function Critmatic.MessageFrame:CreateMessage(text, r, g, b, spellIcon, amount, oldAmount, prevText)
    local MAX_MESSAGES = Critmatic.db.profile.alertNotificationFormat.global.maxMessages
    local delayInSeconds = 0.45
    local function delayedExecution()
        local f = Critmatic.CreateNewMessageFrame()

        f.text:SetTextColor(r, g, b)

        local hasPrev = type(prevText) == "string" and prevText ~= ""
        local _, lineH = f.text:GetFont()
        lineH = lineH or 20
        local gap = 2
        local y1 = hasPrev and (lineH + gap) / 2 or 0
        local y2 = -(lineH + gap) / 2

        if hasPrev then
            f:SetHeight(lineH * 2 + gap + 8)
        end

        local centerOffsetX = 0
        if spellIcon then
            if not f.icon then
                f.icon = f:CreateTexture(nil, "ARTWORK")
                f.icon:SetSize(ICON_SIZE, ICON_SIZE)
            end
            f.icon:SetTexture(spellIcon)
            f.icon:Show()
            centerOffsetX = (ICON_SIZE + ICON_SPACING) / 2

            f.text:SetText(text)
            local textWidth = f.text:GetStringWidth() or 200
            local totalWidth = textWidth + ICON_SIZE + ICON_SPACING
            local iconOffsetX = -(totalWidth / 2) + (ICON_SIZE / 2)

            f.icon:ClearAllPoints()
            f.icon:SetPoint("CENTER", f, "CENTER", iconOffsetX, y1)

            if not f.iconBounce then
                f.iconBounce = f.icon:CreateAnimationGroup()
                local scaleUp = f.iconBounce:CreateAnimation("Scale")
                scaleUp:SetScale(1.5, 1.5)
                scaleUp:SetDuration(0.15)
                scaleUp:SetOrder(1)
                local pause = f.iconBounce:CreateAnimation("Pause")
                pause:SetDuration(0.12)
                pause:SetOrder(2)
                local scaleDown = f.iconBounce:CreateAnimation("Scale")
                scaleDown:SetScale(1 / 1.5, 1 / 1.5)
                scaleDown:SetDuration(0.15)
                scaleDown:SetOrder(3)
            end
            f.iconBounce:Play()
        elseif f.icon then
            f.icon:Hide()
        end

        f.text:ClearAllPoints()
        f.text:SetJustifyH("CENTER")
        f.text:SetPoint("CENTER", f, "CENTER", centerOffsetX, y1)
        f.text:SetText(text)

        if hasPrev then
            if not f.prevText then
                f.prevText = cloneTextStyle(f, "CENTER")
            end
            f.prevText:SetTextColor(r, g, b)
            f.prevText:ClearAllPoints()
            f.prevText:SetJustifyH("CENTER")
            f.prevText:SetPoint("CENTER", f, "CENTER", centerOffsetX, y2)
            f.prevText:SetText(prevText)
            f.prevText:Show()
        elseif f.prevText then
            f.prevText:Hide()
        end

        local cfg = Critmatic.db.profile.alertNotificationFormat.global
        local animated = false
        if cfg.countUpEnabled then
            f.numberCounter = attachCountUpFS(f, f.text, text, amount, y1)
            animated = f.numberCounter ~= nil
            if hasPrev then
                f.prevNumberCounter = attachCountUpFS(f, f.prevText, prevText, oldAmount, y2)
            end
        end

        f.fadeOut = f:CreateAnimationGroup()
        local fade = f.fadeOut:CreateAnimation("Alpha")
        fade:SetFromAlpha(1)
        fade:SetToAlpha(0)
        fade:SetDuration(cfg.fadeTime)
        fade:SetStartDelay(animated and ((cfg.countUpDuration or 3) + (cfg.countUpHold or 3)) or cfg.startDelay)
        f.fadeOut:SetScript("OnFinished", function()
            f:Hide()
            if f.numberCounter then f.numberCounter:Stop() end
            if f.prevNumberCounter then f.prevNumberCounter:Stop() end
        end)

        f.bounce:Play()
        f.fadeOut:Play()

        table.insert(activeMessages, 1, f)
        AdjustMessagePositions()

        if #activeMessages > MAX_MESSAGES then
            RemoveOldestMessage()
        end

        return f
    end

    C_Timer.After(delayInSeconds, delayedExecution)
end
local message = ""
function Critmatic.ShowNewCritMessage(spellName, amount, spellIcon, oldAmount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        message = string.upper(string.format(Critmatic.db.profile.alertNotificationFormat.strings
                                                      .critAlertNotificationFormat, spellName, amount))
    else
        message = string.format(Critmatic.db.profile.alertNotificationFormat.strings.critAlertNotificationFormat,
                spellName, amount)
    end

    local prevText = Critmatic.FormatPreviousRecord(oldAmount, amount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        prevText = string.upper(prevText)
    end

    local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColorCrit)
    Critmatic.MessageFrame:CreateMessage(message, r, g, b, spellIcon, amount, oldAmount, prevText)
end

function Critmatic.ShowNewNormalMessage(spellName, amount, spellIcon, oldAmount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        message = string.upper(string.format(Critmatic.db.profile.alertNotificationFormat.strings
                                                      .hitAlertNotificationFormat, spellName, amount))
    else
        message = string.format(Critmatic.db.profile.alertNotificationFormat.strings.hitAlertNotificationFormat,
                spellName, amount)
    end

    local prevText = Critmatic.FormatPreviousRecord(oldAmount, amount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        prevText = string.upper(prevText)
    end

    local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColor)
    Critmatic.MessageFrame:CreateMessage(message, r, g, b, spellIcon, amount, oldAmount, prevText)
end

function Critmatic.ShowNewHealCritMessage(spellName, amount, spellIcon, oldAmount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        message = string.upper(string.format(Critmatic.db.profile.alertNotificationFormat.strings
                                                      .critHealAlertNotificationFormat, spellName, amount))
    else
        message = string.format(Critmatic.db.profile.alertNotificationFormat.strings.critHealAlertNotificationFormat,
                spellName, amount)
    end

    local prevText = Critmatic.FormatPreviousRecord(oldAmount, amount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        prevText = string.upper(prevText)
    end

    local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColorCrit)
    Critmatic.MessageFrame:CreateMessage(message, r, g, b, spellIcon, amount, oldAmount, prevText)
end

function Critmatic.ShowNewHealMessage(spellName, amount, spellIcon, oldAmount)
    -- Check if the spellName ends with 'Heal', 'heal', or 'HEAL'

    if string.sub(spellName, -4):lower() == "heal" then
        -- Remove the redundant 'Heal' from the format string
        local formatString = Critmatic.db.profile.alertNotificationFormat.strings.healAlertNotificationFormat
        formatString = string.gsub(formatString, "%%s Heal", "%%s")
        formatString = string.gsub(formatString, "%%s heal", "%%s")
        formatString = string.gsub(formatString, "%%s HEAL", "%%s")
        if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
            message = string.upper(string.format(formatString, spellName, amount))
        else

            message = string.format(formatString, spellName, amount)

        end
    else
        if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
            -- If spellName does not end with 'Heal', use the format string as is
            message = string.upper(string.format(Critmatic.db.profile.alertNotificationFormat.strings
                                                          .healAlertNotificationFormat, spellName, amount))
        else
            message = string.format(Critmatic.db.profile.alertNotificationFormat.strings.healAlertNotificationFormat, spellName, amount)

        end
    end

    local prevText = Critmatic.FormatPreviousRecord(oldAmount, amount)
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        prevText = string.upper(prevText)
    end

    local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColor)
    Critmatic.MessageFrame:CreateMessage(message, r, g, b, spellIcon, amount, oldAmount, prevText)
end


