local addonName, private = ...
local AceGUI = LibStub("AceGUI-3.0")
local SharedMedia = LibStub("LibSharedMedia-3.0")
local Type = "AtTextHighlight"
local Version = 1
local variables = {
    text_height = 20,
    text_width = 300,
}


local function ApplySettings(self)
    -- Apply settings to the icon
    if private.db.profile.highlight_text_settings and private.db.profile.highlight_text_settings.font and private.db.profile.highlight_text_settings.fontSize then
        self.frame.SpellName:SetFont(SharedMedia:Fetch("font", private.db.profile.highlight_text_settings.font),
            private.db.profile.highlight_text_settings.fontSize, "OUTLINE")
    elseif private.db.profile.highlight_text_settings and private.db.profile.highlight_text_settings.fontSize then
        self.frame.SpellName:SetFontHeight(private.db.profile.highlight_text_settings.fontSize)
    end

    if private.db.profile.highlight_text_settings and private.db.profile.highlight_text_settings.defaultColor then
        self.frame.SpellName:SetTextColor(
            private.db.profile.highlight_text_settings.defaultColor.r,
            private.db.profile.highlight_text_settings.defaultColor.g,
            private.db.profile.highlight_text_settings.defaultColor.b
        )
    end

    if private.db.profile.highlight_text_settings.useBackground then
        local texture = SharedMedia:Fetch("background", private.db.profile.highlight_text_settings.backgroundTexture)
        self.frame.SpellNameBackground:SetPoint("LEFT", self.frame.SpellName, "LEFT",
            -private.db.profile.highlight_text_settings.backgroundTextureOffset.x, 0)
        self.frame.SpellNameBackground:SetPoint("RIGHT", self.frame.SpellName, "RIGHT",
            private.db.profile.highlight_text_settings.backgroundTextureOffset.x, 0)
        self.frame.SpellNameBackground:SetPoint("TOP", self.frame.SpellName, "TOP", 0,
            private.db.profile.highlight_text_settings.backgroundTextureOffset.y)
        self.frame.SpellNameBackground:SetPoint("BOTTOM", self.frame.SpellName, "BOTTOM", 0,
            -private.db.profile.highlight_text_settings.backgroundTextureOffset.y)
        self.frame.SpellNameBackground:SetTexture(texture)
        self.frame.SpellNameBackground:Show()
    else
        self.frame.SpellNameBackground:Hide()
    end

    if private.db.profile.highlight_text_settings.dispellTextColor then
        for i, _ in pairs(private.dispellTypeList) do
            local coloredSpellName = self.frame.DispellTypeSpellNames[i]
            coloredSpellName:Show()
        end
    else
         for i, _ in pairs(self.frame.DispellTypeSpellNames) do
            self.frame.DispellTypeSpellNames[i]:Hide()
        end
    end
end

---@param self AtTextHighlight
local function OnAcquire(self)
    ApplySettings(self)
end

---@param self AtTextHighlight
local function OnRelease(self)
    self.frame:SetScript("OnUpdate", nil)
    private.HIGHLIGHT_EVENTS.HighlightTexts[self.eventInfo.id] = nil
    for i, f in ipairs(private.HIGHLIGHT_TEXTS) do
        if f == self then
            table.remove(private.HIGHLIGHT_TEXTS, i)
            break
        end
    end
    private.evaluateTextPositions()
end


---comment
---@param self any
---@param remainingTime any
---@return unknown
local GetTextColor = function(self, remainingTime)
    if private.db.profile.cooldown_settings.cooldown_highlight and private.db.profile.cooldown_settings.cooldown_highlight.enabled then
        for _, value in pairs(private.db.profile.cooldown_settings.cooldown_highlight.highlights) do
            local time, color = value.time, value.color
            if (remainingTime <= time) then
                local createdColor = CreateColor(color.r, color.g, color.b)
                return createdColor:GenerateHexColor()
            end
        end
    end
    if private.db.profile.cooldown_settings.cooldown_color then
        local color = private.db.profile.cooldown_settings.cooldown_color
        local createdColor = CreateColor(color.r, color.g, color.b)
        return createdColor:GenerateHexColor()
    end
    return "ffffff"
end
---hides and shows texts to create colored texts (illegal btw)
---@param widget any
---@param eventInfo any
---@param remainingDuration any
local HandleTexts = function(widget, eventInfo, remainingDuration)
    local textColor = GetTextColor(widget, remainingDuration)
    if private.db.profile.highlight_text_settings.dispellTextColor then
        for i, value in pairs(private.dispellTypeList) do
            local coloredSpellName = widget.frame.DispellTypeSpellNames[i]
            C_EncounterTimeline.SetEventIconTextures(eventInfo.id, value.mask, widget.frame.dispellTypeIcons)
            local alpha = widget.frame.dispellTypeIcons[1]:GetAlpha()
            coloredSpellName:SetAlpha(alpha)
        end
    end
    C_EncounterTimeline.SetEventIconTextures(eventInfo.id, 126, widget.frame.dispellTypeIcons)
    local atlas = widget.frame.dispellTypeIcons[1]:GetAtlas()
    local alpha = widget.frame.dispellTypeIcons[1]:GetAlpha()
    local formatedText = string.format("%s in |c%s%i|r", eventInfo.spellName, textColor,
            math.ceil(remainingDuration))
    if private.db.profile.highlight_text_settings.dispellIcons then
         formatedText = string.format("|A:%s:20:20|a %s in |c%s%i|r", atlas, eventInfo.spellName, textColor,
            math.ceil(remainingDuration))
    end
    widget.frame.SpellName:SetText(formatedText)
    if private.db.profile.highlight_text_settings.dispellTextColor then
        -- use desaturation to convert int to boolean to invert using setalpha
        widget.frame.dispellTypeIcons[1]:SetDesaturation(alpha)
        local isDesaturated = widget.frame.dispellTypeIcons[1]:IsDesaturated()
        widget.frame.SpellName:SetAlphaFromBoolean(isDesaturated, 0, 1)
        -- these hacky workarounds are gonna be the death of me
        for i, value in pairs(private.dispellTypeList) do
            local coloredSpellName = widget.frame.DispellTypeSpellNames[i]
            coloredSpellName:SetText(formatedText)
            coloredSpellName:SetTextColor(value.color.r, value.color.g, value.color.b)
        end
    end
end

local SetEventInfo = function(widget, eventInfo, disableOnUpdate)
    widget.eventInfo = eventInfo
    local yOffset = (variables.text_height + private.db.global.text_highlight[private.ACTIVE_EDITMODE_LAYOUT].margin) *
        (#private.HIGHLIGHT_TEXTS)
    widget.yOffset = yOffset
    if not disableOnUpdate then
        HandleTexts(widget, eventInfo, eventInfo.duration)
        widget.frame:SetScript("OnUpdate", function(self)
            local remainingDuration = C_EncounterTimeline.GetEventTimeRemaining(widget.eventInfo.id)
            if not remainingDuration or remainingDuration <= 0 then
                widget:Release()
            else
                HandleTexts(widget, eventInfo, remainingDuration)
            end
        end)
    end
    widget.frame:SetPoint("BOTTOM", private.TEXT_HIGHLIGHT_FRAME.frame, "BOTTOM", 0, yOffset)
    widget.frame:Show()
end

local function Constructor()
    local count = AceGUI:GetNextWidgetNum(Type)
    local frame = CreateFrame("Frame", "HIGHLIGHT_TEXT_" .. count, private.TEXT_HIGHLIGHT_FRAME.frame)
    local yOffset = (variables.text_height + private.db.global.text_highlight[private.ACTIVE_EDITMODE_LAYOUT].margin) *
        (#private.HIGHLIGHT_TEXTS)
    frame.yOffset = yOffset
    frame.SpellName = frame:CreateFontString(nil, "OVERLAY", "SystemFont_Shadow_Med3")
    frame.SpellName:SetWordWrap(false)
    frame.SpellName:SetPoint("CENTER", frame, "CENTER")
    frame.DispellTypeSpellNames = {}

    for i, value in pairs(private.dispellTypeList) do
        local coloredSpellName = frame:CreateFontString(nil, "OVERLAY", "SystemFont_Shadow_Med3")
        coloredSpellName:SetWordWrap(false)
        coloredSpellName:SetPoint("CENTER", frame, "CENTER")
        coloredSpellName:SetTextColor(value.color.r, value.color.g, value.color.b)

        frame.DispellTypeSpellNames[i] = coloredSpellName
    end

    frame.SpellNameBackground = frame:CreateTexture(nil, "BACKGROUND")
    frame.SpellNameBackground:SetPoint("LEFT", frame.SpellName, "LEFT",
        -private.db.profile.highlight_text_settings.backgroundTextureOffset.x, 0)
    frame.SpellNameBackground:SetPoint("RIGHT", frame.SpellName, "RIGHT",
        private.db.profile.highlight_text_settings.backgroundTextureOffset.x, 0)
    frame.SpellNameBackground:SetPoint("TOP", frame.SpellName, "TOP", 0,
        private.db.profile.highlight_text_settings.backgroundTextureOffset.y)
    frame.SpellNameBackground:SetPoint("BOTTOM", frame.SpellName, "BOTTOM", 0,
        -private.db.profile.highlight_text_settings.backgroundTextureOffset.y)
    frame.SpellNameBackground:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
    frame.SpellNameBackground:Hide()
    frame:SetWidth(variables.text_width)
    frame:SetHeight(variables.text_height)
    frame:SetPoint("BOTTOM", private.TEXT_HIGHLIGHT_FRAME.frame, "BOTTOM", 0, yOffset)

    frame.dispellTypeTexture = frame:CreateTexture(nil, "OVERLAY")
    frame.dispellTypeIcons = {}
    table.insert(frame.dispellTypeIcons, frame.dispellTypeTexture)

    ---@class AtTextHighlight : AceGUIWidget
    local widget = {
        OnAcquire = OnAcquire,
        OnRelease = OnRelease,
        type = Type,
        count = count,
        frame = frame,
        SetEventInfo = SetEventInfo,
        eventInfo = {},
        yOffset = 0,
        GetTextColor = GetTextColor,
        ApplySettings = ApplySettings,
    }

    return AceGUI:RegisterAsWidget(widget)
end

AceGUI:RegisterWidgetType(Type, Constructor, Version)
