local _, NSI = ... -- Internal namespace

NSI.EncounterOrder = {
    [3176] = 1, -- Imperator
    [3177] = 2, -- Vorasius
    [3179] = 3, -- Fallen-King
    [3178] = 4, -- Dragons
    [3180] = 5, -- Lightblinded Vanguard
    [3181] = 6, -- Crown of the Cosmos
    [3306] = 7, -- Chimaerus
    [3182] = 8, -- Belo'ren
    [3183] = 9, -- Midnight Falls
}

local symbols = {
    star = 1,
    circle = 2,
    diamond = 3,
    triangle = 4,
    moon = 5,
    square = 6,
    cross = 7,
    skull = 8,
}

function NSI:AddToReminder(info)
    self.ProcessedReminder = self.ProcessedReminder or {}
    self.ProcessedReminder[info.encID] = self.ProcessedReminder[info.encID] or {}
    info.spellID = info.spellID and tonumber(info.spellID)
    -- convert to booleans
    if info.TTS == "true" then info.TTS = true end
    if info.TTS == "false" then info.TTS = false end
    -- default to user settings if not overwritten by the reminders
    if info.TTS == nil then 
        if info.spellID then
            info.TTS = NSRT.ReminderSettings.SpellTTS
        else
            info.TTS = NSRT.ReminderSettings.TextTTS
        end
    end            
    if info.dur == nil then 
        if info.spellID then
             info.dur = NSRT.ReminderSettings.SpellDuration 
        else
            info.dur = NSRT.ReminderSettings.TextDuration 
        end
    end
    if info.countdown == nil then
        if info.spellID then
            info.countdown = NSRT.ReminderSettings.SpellCountdown
        else
            info.countdown = NSRT.ReminderSettings.TextCountdown
        end
        if info.countdown == 0 then info.countdown = false end
    end
    if info.TTSTimer == nil then
        if info.spellID then
            info.TTSTimer = NSRT.ReminderSettings.SpellTTSTimer
        else
            info.TTSTimer = NSRT.ReminderSettings.TextTTSTimer
        end
    end
    info.phase = info.phase and tonumber(info.phase)
    if not info.phase then info.phase = 1 end
    local rawtext = info.text
    if info.text then 
        info.text = info.text:gsub("{(%a+)}", function(name) -- convert {star} to {rt1}, {orange} to {rt2} etc.
            local id = symbols[name]
            if id then
                return "{rt" .. id .. "}"
            end
        end)
        info.text = info.text:gsub("{rt(%d)}", "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%1:0|t")  -- convert {rt1} to the actual icon for display
    end         
    if NSRT.ReminderSettings.SpellName and info.spellID then -- display spellname if text is empty, also make TTS that spellname
        local spell = C_Spell.GetSpellInfo(info.spellID) 
        if spell and not info.text then 
            info.text = spell.name or ""
            info.TTS = info.TTS and type(info.TTS) ~= "string" and spell.name
        end 
    end
    if info.TTS and info.text and type(info.TTS) == "boolean" then
        info.TTS = rawtext
    end
    if info.TTS and type(info.TTS) ~= "string" and info.spellID then -- TTS is enabled but it's still empty, which means text was empty so we should play the spellname TTS instead
        local spell = C_Spell.GetSpellInfo(info.spellID)
        info.TTS = spell and spell.name
    end
    if info.glowunit then
        local glowtable = {}
        for name in glowunit:gmatch("(%w+)") do
            table.insert(glowtable, name)
        end
        info.glowunit = glowtable
    end
    self.ProcessedReminder[info.encID][info.phase] = self.ProcessedReminder[info.encID][info.phase] or {}    
    table.insert(self.ProcessedReminder[info.encID][info.phase], 
    {
        notsticky = info.notsticky,
        BarOverwrite = info.BarOverwrite or info.Type == "Bar", 
        IconOverwrite = info.IconOverwrite or info.Type == "Icon", 
        TTSTimer = info.TTSTimer, 
        rawtext = info.rawtext, 
        phase = info.phase, 
        id = #self.ProcessedReminder[info.encID][info.phase]+1, 
        countdown = info.countdown and tonumber(info.countdown), 
        glowunit = info.glowunit, 
        sound = info.sound, 
        time = tonumber(info.time), 
        text = info.text, 
        TTS = info.TTS, 
        spellID = info.spellID and tonumber(info.spellID), 
        dur = info.dur or 8,
        skipdur = info.skipdur, -- with this true there will be no cooldown edge shown for icons
    })      
end

function NSI:ProcessReminder()
    local str = ""
    self.ProcessedReminder = {}
    if NSRT.ReminderSettings.enabled and self.Reminder then str = self.Reminder end
    if NSRT.ReminderSettings.MRTNote then 
        local note = VMRT and VMRT.Note and VMRT.Note.Text1 or ""
        str = note and str ~= "" and str.."\n"..note or note or str
    end
    if str ~= "" then
        local subgroup = self:GetSubGroup("player")        
        local specid = C_SpecializationInfo.GetSpecializationInfo(C_SpecializationInfo.GetSpecialization())
        local pos = self.spectable[specid]
        local encID = 0
        pos = ((pos <= 19 or pos == 34 or pos == 35) and "melee") or (((pos <= 33 and pos >= 20) or pos >= 36) and "ranged")
        for line in str:gmatch('[^\r\n]+') do
            if line:find("EncounterID:") then
                encID = line:match("EncounterID:(%d+)")
                if encID then encID = tonumber(encID) end
            end
            local tag = line:match("tag:([^;]+)")
            local time = line:match("time:(%d*%.?%d+)")
            local text = line:match("text:([^;]+)")
            local spellID = line:match("spellid:(%d+)")
            if self.TestingReminder and not subgroup then subgroup = 1 end
            if time and tag and subgroup and (text or spellID) and encID and encID ~= 0 then
                tag = strlower(tag)
                if tag == "everyone" or 
                tag:match(strlower(UnitName("player"))) or 
                tag:match(strlower(NSAPI:GetName("player", "GlobalNickNames"))) or 
                tag:match(strlower(UnitGroupRolesAssigned("player"))) or 
                tag:match(specid) or
                tag:match(strlower(select(2, UnitClass("player")))) or
                tag:match("group"..subgroup) or 
                (pos and tag:match(pos))
                then                         
                    local phase = line:match("ph:(%d+)")
                    local TTS = line:match("TTS:([^;]+)")
                    local countdown = line:match("countdown:(%d+)")
                    local dur = line:match("dur:(%d+)")
                    local sound = line:match("sound:([^;]+)")
                    local glowunit = line:match("glowunit:([^;]+)")
                    self:AddToReminder({text = text, phase = phase, countdown = countdown, glowunit = glowunit, sound = sound, time = time, spellID = spellID, dur = dur, TTS = TTS, encID = encID, Type = nil, notsticky = false})
                end
            end
        end
    end
end

function NSI:UpdateExistingFrames() -- called when user changes settings to not require a reload
    local parent = self.ReminderText or {}
    for i=1, #parent do
        local F = parent[i]
        if F and F:IsShown() then
            local s = NSRT.ReminderSettings.TextSettings
            local offset = s.GrowDirection == "Up" and (i-1) * s.FontSize or -(i-1) * s.FontSize
            F.Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
        end
    end
    self:ArrangeStates("Texts")
    self:MoveFrameSettings(self.TextMover, NSRT.ReminderSettings.TextSettings, true) 
    parent = self.ReminderIcon or {}
    for i=1, #parent do
        local F = parent[i]
        if F and F:IsShown() then
            local s = NSRT.ReminderSettings.IconSettings
            F:SetSize(s.Width, s.Height)
            local offset = s.GrowDirection == "Up" and (i-1) * s.Height or -(i-1) * s.Height
            F.Icon:SetAllPoints(F)
            F.Border:SetAllPoints(F)
            F.Text:SetPoint("LEFT", F, "RIGHT", s.xTextOffset, s.yTextOffset)
            F.Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
            F.TimerText:SetPoint("CENTER", F.Swipe, "CENTER", s.xTimer, s.yTimer)
            F.TimerText:SetFont(self.LSM:Fetch("font", s.Font), s.TimerFontSize, "OUTLINE")
        end
    end
    self:ArrangeStates("Icons")
    self:MoveFrameSettings(self.IconMover, NSRT.ReminderSettings.IconSettings) 
    parent = self.UnitIcon or {}
    for i=1, #parent do
        local F = parent[i]
        if F and F:IsShown() then
            local s = NSRT.ReminderSettings.UnitIconSettings
            F:SetSize(s.Width, s.Height) -- not setting points in this one because this is repeated every time the frame is shown as it needs a new frame to anchor to anyway
        end
    end
    parent = self.ReminderBar or {}
    for i=1, #parent do
        local F = parent[i]
        if F and F:IsShown() then
            local s = NSRT.ReminderSettings.BarSettings
            F:SetSize(s.Width, s.Height)
            F:SetStatusBarTexture(self.LSM:Fetch("statusbar", s.Texture))
            F:SetStatusBarColor(unpack(F.info.colors or s.colors))
            local offset = s.GrowDirection == "Up" and (i-1) * s.Height or -(i-1) * s.Height
            F.Border:SetAllPoints(F)
            F.Icon:SetPoint("RIGHT", F, "LEFT", s.xIcon, s.yIcon)
            F.Icon:SetSize(s.Height, s.Height)
            F.Text:SetPoint("LEFT", F.Icon, "RIGHT", s.xTextOffset, s.yTextOffset)
            F.Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
            F.TimerText:SetPoint("RIGHT", F, "RIGHT", s.xTimer, s.yTimer)
            F.TimerText:SetFont(self.LSM:Fetch("font", s.Font), s.TimerFontSize, "OUTLINE")
        end
    end
    self:ArrangeStates("Bars")
    self:MoveFrameSettings(self.BarMover, NSRT.ReminderSettings.BarSettings) 
end

function NSI:ArrangeStates(Type)
    local F = (Type == "Texts" and self.ReminderText) or (Type == "Icons" and self.ReminderIcon) or (Type == "Bars" and self.ReminderBar)
    if not F then return end
    local s = (Type == "Texts" and NSRT.ReminderSettings.TextSettings) or (Type == "Icons" and NSRT.ReminderSettings.IconSettings) or (Type == "Bars" and NSRT.ReminderSettings.BarSettings)
    local pos = {}
    for i=1, #F do
        if F[i] and F[i]:IsShown() then
            table.insert(pos, {Frame = F[i], id = F[i].info.id, expires = F[i].info.expires})
        end
    end
    table.sort(pos, function(a, b) 
        if a.expires == b.expires then
            return a.id < b.id
        else
            return a.expires < b.expires
        end
    end)
    for i, v in ipairs(pos) do
        local diff = Type == "Texts" and s.FontSize or s.Height
        local offset = s.GrowDirection == "Up" and (i-1) * diff or -(i-1) * diff
        v.Frame:ClearAllPoints()
        if Type == "Texts" then
            v.Frame:SetPoint("BOTTOMLEFT", "NSUIReminderTextMover", "BOTTOMLEFT", 0, 0 + offset)
            v.Frame:SetPoint("TOPRIGHT", "NSUIReminderTextMover", "TOPRIGHT", 0, 0 + offset)
        elseif Type == "Icons" then
            v.Frame:SetPoint("BOTTOMLEFT", "NSUIReminderIconMover", "BOTTOMLEFT", 0, 0 + offset)
            v.Frame:SetPoint("TOPRIGHT", "NSUIReminderIconMover", "TOPRIGHT", 0, 0 + offset)
        elseif Type == "Bars" then
            v.Frame:SetPoint("BOTTOMLEFT", "NSUIReminderBarMover", "BOTTOMLEFT", 0, 0 + offset)
            v.Frame:SetPoint("TOPRIGHT", "NSUIReminderBarMover", "TOPRIGHT", 0, 0 + offset)
        else
            print("RELOE PLS FIX (Reminder anchoring issue @ NSI:ArrangeStates)")
        end
    end
end

function NSI:SetProperties(F, info, skipsound, s)
    F:SetScript("OnUpdate", function()
        NSI:UpdateReminderDisplay(info, F, skipsound)
    end)
    F:SetScript("OnHide", function()        
        if info.glowunit then
            NSI:HideGlows(info.glowunit, "p"..info.phase.."id"..info.id)
        end
        NSI:ArrangeStates(F.Type)
    end)    
    F.info = info
    if not info.spellID then return end
    local icon = C_Spell.GetSpellInfo(info.spellID).iconID    
    F.Icon:SetTexture(icon)
    if F.Swipe then 
        if info.skipdur then
            F.Swipe:SetCooldown(0, 0) 
            F.TimerText:Hide()
        else
            F.Swipe:SetCooldown(GetTime(), info.dur) 
            if NSRT.ReminderSettings.HideTimerText then 
                F.TimerText:Hide() 
            else
                F.TimerText:SetTextColor(1, 1, 0, 1)
            end
        end
    elseif F.TimerText then
        F.TimerText:SetTextColor(1, 1, 1, 1)
    end
    F:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
    F:SetScript("OnEvent", function(self, e, ...)
        local unit, _, spellID = ...
        if (NSI:IsMidnight() and (not issecretvalue(spellID)) and (not issecretvalue(info.spellID))) and spellID == info.spellID and UnitIsUnit("player", unit) and self:IsShown() then
            self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED")
            self:Hide()
        end
    end)
end

function NSI:CreateText(info)
    self.ReminderText = self.ReminderText or {}    
    local s = NSRT.ReminderSettings.TextSettings
    for i=1, #self.ReminderText+1 do
        if self.ReminderText[i] and not self.ReminderText[i]:IsShown() then 
            self:SetProperties(self.ReminderText[i], info, false, s)
            return self.ReminderText[i] 
        end
        if not self.ReminderText[i] then      
            self.ReminderText[i] = CreateFrame("Frame", 'NSUIReminderText' .. i, UIParent, "BackdropTemplate")
            local offset = s.GrowDirection == "Up" and (i-1) * s.FontSize or -(i-1) * s.FontSize
            self.ReminderText[i]:SetPoint("BOTTOMLEFT", "NSUIReminderTextMover", "BOTTOMLEFT", 0, 0 + offset)
            self.ReminderText[i]:SetPoint("TOPRIGHT", "NSUIReminderTextMover", "TOPRIGHT", 0, 0 + offset)
            self.ReminderText[i].Text = self.ReminderText[i]:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            self.ReminderText[i].Text:SetPoint("LEFT", self.ReminderText[i], "LEFT", 0, 0)
            self.ReminderText[i].Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
            self.ReminderText[i].Text:SetShadowColor(0, 0, 0, 1)
            self.ReminderText[i].Text:SetShadowOffset(0, 0)
            self.ReminderText[i].Text:SetTextColor(1, 1, 1, 1)
            self:SetProperties(self.ReminderText[i], info, false, s)
            return self.ReminderText[i]
        end
    end
end

function NSI:CreateIcon(info)
    self.ReminderIcon = self.ReminderIcon or {}
    local icon = C_Spell.GetSpellInfo(info.spellID).iconID
    local s = NSRT.ReminderSettings.IconSettings
    for i=1, #self.ReminderIcon+1 do
        if self.ReminderIcon[i] and not self.ReminderIcon[i]:IsShown() then 
            self:SetProperties(self.ReminderIcon[i], info, false, s)
            return self.ReminderIcon[i] 
        end
        if not self.ReminderIcon[i] then
            self.ReminderIcon[i] = CreateFrame("Frame", 'NSUIReminderIcon' .. i, UIParent, "BackdropTemplate")
            local offset = s.GrowDirection == "Up" and (i-1) * s.Height or -(i-1) * s.Height
            self.ReminderIcon[i]:SetPoint("BOTTOMLEFT", "NSUIReminderIconMover", "BOTTOMLEFT", 0, 0 + offset)
            self.ReminderIcon[i]:SetPoint("TOPRIGHT", "NSUIReminderIconMover", "TOPRIGHT", 0, 0 + offset)
            self.ReminderIcon[i].Icon = self.ReminderIcon[i]:CreateTexture(nil, "ARTWORK")
            self.ReminderIcon[i].Icon:SetAllPoints(self.ReminderIcon[i])
            self.ReminderIcon[i].Border = CreateFrame("Frame", nil, self.ReminderIcon[i], "BackdropTemplate")
            self.ReminderIcon[i].Border:SetAllPoints(self.ReminderIcon[i])
            self.ReminderIcon[i].Border:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1
            })
            self.ReminderIcon[i].Border:SetBackdropBorderColor(0, 0, 0, 1)
            self.ReminderIcon[i].Text = self.ReminderIcon[i]:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            self.ReminderIcon[i].Text:SetPoint("LEFT", self.ReminderIcon[i], "RIGHT", s.xTextOffset, s.yTextOffset)
            self.ReminderIcon[i].Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
            self.ReminderIcon[i].Text:SetShadowColor(0, 0, 0, 1)
            self.ReminderIcon[i].Text:SetShadowOffset(0, 0)
            self.ReminderIcon[i].Text:SetTextColor(1, 1, 1, 1)
            self.ReminderIcon[i].Swipe = CreateFrame("Cooldown", nil, self.ReminderIcon[i], "CooldownFrameTemplate")
            self.ReminderIcon[i].Swipe:SetAllPoints()
            self.ReminderIcon[i].Swipe:SetDrawBling(false)
            self.ReminderIcon[i].Swipe:SetDrawEdge(false)
            self.ReminderIcon[i].Swipe:SetReverse(true)
            self.ReminderIcon[i].Swipe:SetHideCountdownNumbers(true)
            self.ReminderIcon[i].TimerText = self.ReminderIcon[i].Swipe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            self.ReminderIcon[i].TimerText:SetPoint("CENTER", self.ReminderIcon[i].Swipe, "CENTER", s.xTimer, s.yTimer)
            self.ReminderIcon[i].TimerText:SetFont(self.LSM:Fetch("font", s.Font), s.TimerFontSize, "OUTLINE")
            self.ReminderIcon[i].TimerText:SetShadowColor(0, 0, 0, 1)
            self.ReminderIcon[i].TimerText:SetShadowOffset(0, 0)
            self.ReminderIcon[i].TimerText:SetDrawLayer("OVERLAY", 7)                        
            self:SetProperties(self.ReminderIcon[i], info, false, s)
            return self.ReminderIcon[i]
        end
    end
end



function NSI:CreateUnitFrameIcon(info, name)    
    self.UnitIcon = self.UnitIcon or {}
    local icon = C_Spell.GetSpellInfo(info.spellID).iconID    
    local unit = NSAPI:GetChar(name, true)
    local i = UnitInRaid(unit)
    if (not UnitExists(unit)) or (not i) then return end
    local F = self.RaidFrames["raid"..i]
    if not F then return end
    local s = NSRT.ReminderSettings.UnitIconSettings
    for i=1, #self.UnitIcon+1 do
        if self.UnitIcon[i] and not self.UnitIcon[i]:IsShown() then 
            self.UnitIcon[i]:ClearAllPoints()
            self.UnitIcon[i]:SetPoint(s.Position, F, s.Position, s.xOffset, s.yOffset)
            self:SetProperties(self.UnitIcon[i], info, true, s)
            return self.UnitIcon[i] 
        end
        if not self.UnitIcon[i] then            
            self.UnitIcon[i] = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
            self.UnitIcon[i]:SetSize(s.Width, s.Height)
            self.UnitIcon[i]:SetPoint(s.Position, F, s.Position, s.xOffset, s.yOffset)
            self.UnitIcon[i].Icon = self.UnitIcon[i]:CreateTexture(nil, "ARTWORK")
            self.UnitIcon[i].Icon:SetAllPoints(self.UnitIcon[i])
            self.UnitIcon[i].Icon:SetTexture(icon)
            self.UnitIcon[i].Border = CreateFrame("Frame", nil, self.UnitIcon[i], "BackdropTemplate")
            self.UnitIcon[i].Border:SetAllPoints(self.UnitIcon[i])
            self.UnitIcon[i].Border:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1
            })
            self.UnitIcon[i].Border:SetBackdropBorderColor(0, 0, 0, 1)       
            self:SetProperties(self.UnitIcon[i], info, true, s)
            return self.UnitIcon[i]
        end
    end
end

function NSI:CreateBar(info)
    self.ReminderBar = self.ReminderBar or {}
    local icon = C_Spell.GetSpellInfo(info.spellID).iconID
    local s = NSRT.ReminderSettings.BarSettings
    for i=1, #self.ReminderBar+1 do
        if self.ReminderBar[i] and not self.ReminderBar[i]:IsShown() then                 
            self:SetProperties(self.ReminderBar[i], info, false, s)
            return self.ReminderBar[i] 
        end
        if not self.ReminderBar[i] then            
            self.ReminderBar[i] = CreateFrame("StatusBar", 'NSUIReminderBar' .. i, UIParent, "BackdropTemplate")
            self.ReminderBar[i]:SetBackdrop({ 
            bgFile = "Interface\\Buttons\\WHITE8x8", 
            tileSize = 0,
            })
            self.ReminderBar[i]:SetStatusBarTexture(self.LSM:Fetch("statusbar", s.Texture))
            self.ReminderBar[i]:SetStatusBarColor(unpack(info.colors or s.colors))
            self.ReminderBar[i]:SetBackdropColor(0, 0, 0, 0.8)
            local offset = s.GrowDirection == "Up" and (i-1) * s.Height or -(i-1) * s.Height
            self.ReminderBar[i]:SetPoint("BOTTOMLEFT", "NSUIReminderBarMover", "BOTTOMLEFT", 0, 0 + offset)
            self.ReminderBar[i]:SetPoint("TOPRIGHT", "NSUIReminderBarMover", "TOPRIGHT", 0, 0 + offset)
            self.ReminderBar[i].Border = CreateFrame("Frame", nil, self.ReminderBar[i], "BackdropTemplate")
            self.ReminderBar[i].Border:SetAllPoints(self.ReminderBar[i])
            self.ReminderBar[i].Border:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1
            })
            self.ReminderBar[i].Border:SetBackdropBorderColor(0, 0, 0, 1)
            self.ReminderBar[i].Icon = self.ReminderBar[i]:CreateTexture(nil, "ARTWORK")
            self.ReminderBar[i].Icon:SetPoint("RIGHT", self.ReminderBar[i], "LEFT", s.xIcon, s.yIcon)
            self.ReminderBar[i].Icon:SetSize(s.Height, s.Height)
            self.ReminderBar[i].Text = self.ReminderBar[i]:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            self.ReminderBar[i].Text:SetPoint("LEFT", self.ReminderBar[i].Icon, "RIGHT", s.xTextOffset, s.yTextOffset)
            self.ReminderBar[i].Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
            self.ReminderBar[i].Text:SetShadowColor(0, 0, 0, 1)
            self.ReminderBar[i].Text:SetShadowOffset(0, 0)
            self.ReminderBar[i].Text:SetTextColor(1, 1, 1, 1)
            self.ReminderBar[i].TimerText = self.ReminderBar[i]:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            self.ReminderBar[i].TimerText:SetPoint("RIGHT", self.ReminderBar[i], "RIGHT", s.xTimer, s.yTimer)
            self.ReminderBar[i].TimerText:SetFont(self.LSM:Fetch("font", s.Font), s.TimerFontSize, "OUTLINE")
            self.ReminderBar[i].TimerText:SetShadowColor(0, 0, 0, 1)
            self.ReminderBar[i].TimerText:SetShadowOffset(0, 0)            
            self:SetProperties(self.ReminderBar[i], info, false, s)
            return self.ReminderBar[i]
        end
    end
end

function NSI:DisplayReminder(info)
    local now = GetTime()
    local dur = info.dur or 8
    info.startTime = now
    info.dur = dur
    info.expires = now + dur
    local rem = info.dur - (now - info.startTime)
    if info.spellID and rem <= (0-NSRT.ReminderSettings.Sticky) or ((info.notsticky or not info.spellID) and rem <= 0) then
        return
    end
    local remString
    if rem < 3 then
        if rem < 0 then 
            remString = "" 
        else
            rem = math.floor(rem * 10 + 0.5) / 10
            remString = string.format("%.1f", rem)
        end
    else
        remString = tostring(math.ceil(rem))
    end
    local remString = (rem % 1 == 0) and string.format("%.1f", rem) or rem
    local text = info.text ~= "" and info.text or ""
    local F    
    if info.spellID then -- display icon if we have a spellID    
        if (NSRT.ReminderSettings.Bars or info.BarOverwrite) and not info.IconOverwrite then
            F = self:CreateBar(info)
            F:SetMinMaxValues(0, info.dur)
            F:SetValue(0)
            F:Show()
            self:ArrangeStates("Bars")
            F.Type = "Bars"
        else
            F = self:CreateIcon(info)
            F:Show()
            self:ArrangeStates("Icons")
            F.Type = "Icons"
        end
        F.Text:SetText(text)
        F.TimerText:SetText(remString)
    else
        F = self:CreateText(info)
        F.Type = "Texts"
        F.Text:SetText(text.." - ("..remString..")" or remString)
        F:Show()
        self:ArrangeStates("Texts")
    end    
    if info.glowunit then
        for i, name in ipairs(info.glowunit) do
            self:GlowFrame(name, "p"..info.phase.."id"..info.id)
            if info.spellID then
                local UnitIcon = self:CreateUnitFrameIcon(info, name) 
                if UnitIcon then UnitIcon:Show() end
            end
        end
    end
end

function NSI:UpdateReminderDisplay(info, F, skipsound)
    local rem = info.dur - (GetTime() - info.startTime)
    local SoundTimer = info.TTSTimer or (info.spellID and NSRT.ReminderSettings.SpellTTSTimer or NSRT.ReminderSettings.TextTTSTimer)
    if rem <= SoundTimer and (not self.PlayedSound["ph"..info.phase.."id"..info.id]) and (not skipsound) then
        self:PlayReminderSound(info)
        self.PlayedSound["ph"..info.phase.."id"..info.id] = true
    end
    if info.countdown and rem <= info.countdown and (not self.StartedCountdown["ph"..info.phase.."id"..info.id]) and (not skipsound) then
        NSAPI:TTSCountdown(info.countdown)
        self.StartedCountdown["ph"..info.phase.."id"..info.id] = true
    end
    if info.spellID and rem <= (0-NSRT.ReminderSettings.Sticky) or ((info.notsticky or not info.spellID) and rem <= 0) then
        F:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED")
        F:Hide()
        return
    end
    local remString
    if rem < 3 then
        if rem < 0 then 
            remString = "" 
        else
            rem = math.floor(rem * 10 + 0.5) / 10
            remString = string.format("%.1f", rem)
        end
    else
        remString = tostring(math.ceil(rem))
    end
    local text = info.text and info.text ~= "" and info.text.." - ("..remString..")" or remString
    if info.spellID and type(info.spellID) == "number" then
        if F:GetObjectType() == "StatusBar" then
            F:SetValue((GetTime()-info.startTime))
        else
            if rem <= 3 and F.TimerText then
                F.TimerText:SetTextColor(1, 0, 0, 1)
            end
        end
        if F.TimerText then F.TimerText:SetText(remString) end
    else
        F.Text:SetText(text)
    end    
end

function NSI:PlayReminderSound(info, default)
    if default then -- so I can use this function outside of reminders basically
        info = {sound = default, TTS = default, rawtext = default}
    end
    local sound = info.sound and self.LSM:Fetch("sound", info.sound)
    if sound and sound ~= 1 then
        PlaySoundFile(sound, "Master")
        return      
    elseif info.TTS then
        local TTS = (type(info.TTS) == "string" and info.TTS) or (info.rawtext and info.rawtext ~= "" and info.rawtext) or ""
        sound = self.LSM:Fetch("sound", TTS)
        if sound and sound ~= 1 then
            PlaySoundFile(sound, "Master")
            return
        else
            NSAPI:TTS(TTS)
        end
    end
end

function NSI:StartReminders(phase)
    self:HideAllReminders()
    self.AllGlows = {}
    self.ReminderTimer = {}    
    if not self.EncounterID then return end
    if not self.ProcessedReminder[self.EncounterID] then return end
    if not self.ProcessedReminder[self.EncounterID][phase] then return end
    for i, v in ipairs(self.ProcessedReminder[self.EncounterID][phase]) do
        local time = math.max(v.time-v.dur, 0)
        self.ReminderTimer[i] = C_Timer.NewTimer(time, function()
            if self:Restricted() or self.TestingReminder then 
                self:DisplayReminder(v) 
            else
                self:HideAllReminders()
            end
        end)
    end
end

function NSI:HideAllReminders()
    self.PlayedSound = {}
    self.StartedCountdown = {}
    if self.ReminderTimer then
        for i, v in ipairs(self.ReminderTimer) do
            v:Cancel()
        end
    end
    if self.AllGlows then
        for k, v in pairs(self.AllGlows) do
            self.LCG.PixelGlow_Stop(k, v)
        end
    end
    local parent = self.ReminderText or {}
    for i=1, #parent do
        local F = parent[i]
        if F then F:Hide() end
    end
    parent = self.ReminderIcon or {}
    for i=1, #parent do
        local F = parent[i]
        if F then F:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") F:Hide() end
    end
    parent = self.ReminderBar or {}
    for i=1, #parent do
        local F = parent[i]
        if F then F:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") F:Hide() end
    end
    parent = self.UnitIcon or {}
    for i=1, #parent do
        local F = parent[i]
        if F then F:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") F:Hide() end
    end
end

function NSI:GetAllReminderNames()
    local list = {}
    for k, v in pairs(NSRT.Reminders) do
        local encID = v:match("EncounterID:(%d+)")
        if encID then
            encID = self.EncounterOrder[tonumber(encID)]
            table.insert(list, {name = k, order = encID})
        end
    end
    table.sort(list, function(a, b) 
        if a.order == b.order then
            return a.name < b.name
        else
            return a.order < b.order 
        end
    end)
    return list
end

function NSI:SetReminder(name)
    if name and NSRT.Reminders[name] then
        self.Reminder = NSRT.Reminders[name]
        NSRT.ActiveReminder = name
        self:ProcessReminder()
    end
end

function NSI:RemoveReminder(name)
    if name and NSRT.Reminders[name] then
        NSRT.Reminders[name] = nil
        if NSRT.ActiveReminder == name then
            self.Reminder = ""
            NSRT.ActiveReminder = ""
        end
    end
end

function NSI:ImportFullReminderString(str)
    local name = ""
    local values = ""
    for line in str:gmatch('[^\r\n]+') do
        if line:find("EncounterID:") and line:find("Name:") then
            if values ~= "" then -- meaning we reached a new boss line as the previous one has values already
                self:ImportReminder(name, values)
                values = ""
            end
            name = line:match("Name:([^;]+)")
            values = line.."\n"
        elseif name ~= "" then
            values = values..line.."\n"
        end
    end
    if values ~= "" and name ~= "" then -- importing the last boss
        self:ImportReminder(name, values)
    end
end

function NSI:ImportReminder(name, values, activate)
    if not name then name = "Default Reminder" end
    if NSRT.Reminders[name] and not name == "Default Reminder" then -- for default reminder we just overwrite for now
        self:ImportReminder(name.." 2", values, activate)
        return
    end
    NSRT.Reminders[name] = values
    if activate then
        self:SetReminder(name)
    end
    -- NSI:UpdateReminderList()
end

function NSI:GlowFrame(unit, id)
    local color = {0, 1, 0, 1}
    if not unit then return end
    unit = NSAPI:GetChar(unit, true)
    local i = UnitInRaid(unit)
    if (not UnitExists(unit)) or (not i) then return end
    id = unit..id
    local F = self.RaidFrames["raid"..i]
    if not F then return end
    self.LCG.PixelGlow_Stop(F, id) -- hide any preivous glows first
    self.AllGlows[F] = id
    local s = NSRT.ReminderSettings.GlowSettings
    self.LCG.PixelGlow_Start(F, s.colors, s.Lines, s.Frequency, s.Length, s.Thickness, s.xOffset, s.yOffset, true, id)
end

function NSI:HideGlows(units, id)    
    if not units then return end
    for i, unit in ipairs(units) do
        unit = NSAPI:GetChar(unit, true)
        local i = UnitInRaid(unit)
        if (not UnitExists(unit)) or (not i) then return end
        local newid = unit..id
        local F = self.RaidFrames["raid"..i]
        if not F then return end
        self.AllGlows[F] = nil
        self.LCG.PixelGlow_Stop(F, newid) 
    end
end

function NSI:StoreFrames(init)
    if self:Restricted() then return end
    self.RaidFrames = {}
    if init then
        local MyFrame = self.LGF.GetUnitFrame("player")
        if self.FrameStoreTimer then self.FrameStoreTimer:Cancel() end
        self.FrameStoreTimer = C_Timer.NewTimer(1, function()
            NSI:StoreFrames(false)
        end)
        return
    end
    for unit in self:IterateGroupMembers() do
        local F = self.LGF.GetUnitFrame(unit)
        if F then
            self.RaidFrames[unit] = F
        end
    end
end

function NSI:CreateMoveFrames(Show)
    if not self.IconMover then
        self.IconMover = CreateFrame("Frame", 'NSUIReminderIconMover', UIParent, "BackdropTemplate")
        self:MoveFrameInit(self.IconMover, "IconSettings")
        self:MoveFrameSettings(self.IconMover, NSRT.ReminderSettings.IconSettings)
    else
        self:MoveFrameSettings(self.IconMover, NSRT.ReminderSettings.IconSettings)
    end
    if not self.BarMover then
        self.BarMover = CreateFrame("Frame", 'NSUIReminderBarMover', UIParent, "BackdropTemplate")
        self:MoveFrameInit(self.BarMover, "BarSettings")
        self:MoveFrameSettings(self.BarMover, NSRT.ReminderSettings.BarSettings)
    else
        self:MoveFrameSettings(self.BarMover, NSRT.ReminderSettings.BarSettings)
    end
     if not self.TextMover then
        self.TextMover = CreateFrame("Frame", 'NSUIReminderTextMover', UIParent, "BackdropTemplate")
        self.TextMover.Text = self.TextMover:CreateFontString('TextMoverText', "OVERLAY", "GameFontNormal")
        self.TextMover.Text:SetPoint("LEFT", self.TextMover, "LEFT", 0, 0)
        self.TextMover.Text:SetTextColor(1, 1, 1, 0)
        self:MoveFrameInit(self.TextMover, "TextSettings", true)   
        self:MoveFrameSettings(self.TextMover, NSRT.ReminderSettings.TextSettings, true)   
    else
        local s = NSRT.ReminderSettings.TextSettings 
        self.TextMover.Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")      
        self:MoveFrameSettings(self.TextMover, s, true)
    end

    self.IconMover:Show()
    self.BarMover:Show()
    self.TextMover:Show()
    self.IconMover.Border:Hide()
    self.BarMover.Border:Hide()
    self.TextMover.Border:Hide()
end        



function NSI:MoveFrameSettings(F, s, text)    
    if text then        
        F.Text:SetFont(self.LSM:Fetch("font", s.Font), s.FontSize, "OUTLINE")
        F.Text:SetText("Personals - (10)")
        s.Width, s.Height = F.Text:GetStringWidth(), F.Text:GetStringHeight()   
    end
    F:SetSize(s.Width, s.Height)
    F:ClearAllPoints()
    F:SetPoint(s.Anchor, UIParent, s.relativeTo, s.xOffset, s.yOffset)
    F.Border:ClearAllPoints()
    F.Border:SetAllPoints(F)
end

function NSI:MoveFrameInit(F, s, text)
    if F then             
        F.Border = CreateFrame("Frame", nil, F, "BackdropTemplate") 
        F.Border:SetAllPoints(F)
        F.Border:SetBackdrop({
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 2
            })
        F.Border:SetBackdropBorderColor(1, 1, 1, 1)  
        F.Border:Hide()
        F:SetFrameStrata("DIALOG")
        F:SetScript("OnDragStart", function(self)
            self:StartMoving()
        end)
        F:SetScript("OnDragStop", function(Frame)
            Frame:StopMovingOrSizing()       
            local Anchor, _, relativeTo, xOffset, yOffset = Frame:GetPoint()
            xOffset = Round(xOffset)
            yOffset = Round(yOffset)
            NSRT.ReminderSettings[s].xOffset = xOffset     
            NSRT.ReminderSettings[s].yOffset = yOffset  
            NSRT.ReminderSettings[s].Anchor = Anchor    
            NSRT.ReminderSettings[s].relativeTo = relativeTo    
            self:UpdateExistingFrames() 
        end)
    end
end

function NSI:ToggleMoveFrames(F, Unlock)
    if Unlock then
        F:SetMovable(true)
        F:EnableMouse(true)
        F:RegisterForDrag("LeftButton")
        F:SetClampedToScreen(true)
        F.Border:Show()
    else
        F.Border:Hide()
        F:SetMovable(false)
        F:EnableMouse(false)
    end    
end

function NSAPI:DebugNextPhase(num)
    for i=1, num do
        NSI:EventHandler("ENCOUNTER_TIMELINE_EVENT_ADDED")
    end
end

function NSAPI:DebugReminder(EncounterID, startnow, nextphase)
    if NSRT.Settings["Debug"] then
        if not NSI.EncounterDetections[EncounterID] then
            NSI.EncounterDetections[EncounterID] = {0, 8, 8, 8}
        end
        if (not NSI.Reminder) or NSI.Reminder == "" then -- default to preset reminders if none were set
            local text = "EncounterID:"..EncounterID.."\nph:1;time:10;tag:Senfi Group1;text:Stack on {rt7};sound:Stack;countdown:3;TTS:Stack on Red;dur:8;"
            text = text.."\n".."time:15;tag:monk;TTS:true;spellid:115203;"
            text = text.."\n".."ph:1;time:25;tag:everyone;text:Lust on Reloe;glowunit:Reloe;spellid:116841;TTS:true;"
            text = text.."\n".."ph:2;time:10;tag:Reloe;text:Spread;TTS:true;dur:10;"
            text = text.."\n".."ph:2;time:15;tag:268;text:Run out if Debuff;TTS:true;dur:10"
            text = text.."\n".."ph:2;time:25;tag:tank;text:Use Ring;TTS:true;spellid:116844;dur:10;"
            NSI.Reminder = text
        end
        NSI:ProcessReminder()
        if startnow then -- not doing encounter start to specifically test reminders instead of also having assignments
            NSI.EncounterID = EncounterID
            NSI.Phase = 1
            NSI.PhaseSwapTime = GetTime()
            NSI.ReminderText = NSI.ReminderText or {}
            NSI.ReminderIcon = NSI.ReminderIcon or {}
            NSI.ReminderBar = NSI.ReminderBar or {}
            NSI.ReminderTimer = NSI.ReminderTimer or {}
            NSI.RaidFrames = NSI.RaidFrames or {}
            NSI.AllGlows = NSI.AllGlows or {}
            NSI.PlayedSound = {}
            NSI.StartedCountdown = {}
            NSI.Timelines = {}
            NSI.TimeLinesDebug = {}
            NSI:StartReminders(NSI.Phase)
            if not nextphase then return end
            C_Timer.After(40, function()
                NSAPI:DebugNextPhase(10)
            end)
        end
    end
end

function NSAPI:DebugEncounter(EncounterID)
    if NSRT.Settings["Debug"] then
        NSI.ProcessedReminder = {}
        NSI:EventHandler("ENCOUNTER_START", true, true, EncounterID)
    end
end

-- /run NSAPI:DebugReminder(3306)
-- /run NSAPI:DebugReminder(3176)
-- /run NSAPI:DebugReminder(3177)
-- /run NSAPI:DebugReminder(3179)
-- /run NSAPI:DebugReminder(3182)
-- /run NSAPI:DebugReminder(3178)
-- /run NSAPI:DebugReminder(3180)
-- /run NSAPI:DebugReminder(2900)

-- Import this string and then run debug (need to be in raidgroup)
--[[
EncounterID:2900
ph:1;time:10;tag:Senfi Group1;text:Stack on {cross};sound:Stack;countdown:3;dur:8;
time:15;tag:monk;TTS:true;spellid:115203;
ph:1;time:25;tag:everyone;text:Lust on Reloe;glowunit:Reloe;spellid:116841;TTS:true;

/run NSAPI:DebugReminder(3306, true, false)
]]

function NSI:CreateDefaultAlert(text, Type, spellID, dur, phase, encID)
    local info = 
    {
        dur = dur,
        spellID = spellID,
        encID = encID,
        TTSTimer = 60, -- tts on show
        text = text, 
        TTS = text, 
        notsticky = true, 
        phase = phase or self.Phase,
        id = 0, 
        startTime = GetTime(),
    }
    if Type == "Bar" then info.BarOverwrite = true
    elseif Type == "Icon" then info.IconOverwrite = true
    end
    return info
end