local listener = PlayerAuras;

local defaultSettings = {
    ["blocked-Buffs"] = {},
    ["blocked-Debuffs"] = {},
    ["userAnchors-Buffs"] = {},
    ["userAnchors-Debuffs"] = {},
    isAnnouncing = true,
    buffsName = "Buffs",
    debuffsName = "Debuffs",
    ["standardAnnounce-Buffs"] = "My %s will expire in %d.",
    ["noDurationAnnounce-Buffs"] = "I have the %s buff.",
    ["standardAnnounce-Debuffs"] = "My %s will expire in %d.",
    ["noDurationAnnounce-Debuffs"] = "I'm afflicted by the %s debuff.",
    ["standardSetting-Buffs"] = nil,
    ["standardSetting-Debuffs"] = nil,
    ["noDurSetting-Buffs"] = nil,
    ["noDurSetting-Debuffs"] = nil,
};

function listener:FindAnchor(name, target, duration)
    name = string.lower(name);
    local default, noDurLoc;
    for anchor, settings in pairs(self:Get("userAnchors-" .. target)) do
        if duration == nil and settings.noDurLoc then
            noDurLoc = anchor;
        end
        if settings.timers then
            for entry in pairs(settings.timers) do
                if string.find(name, entry) then
                    return anchor;
                end
            end
        end
        if settings.default then default = anchor; end
    end
    
    return noDurLoc or default;
end

function listener:FindTimerSettings(name, anchor, target, duration)
    name = string.lower(name);
    local settings = self:Get("userAnchors-" .. target, anchor);
    if settings.timerSettings then
        for setting, entries in pairs(settings.timerSettings) do
            for entry in pairs(entries) do
                if string.find(name, entry) then
                    return setting;
                end
            end
        end
    end
    local setting = "standardSetting-" .. target;
    if not duration then
        setting = "noDurSetting-" .. target;
    end
    return self:Get(setting);
end

function listener:MakeTimer(target, timer)
    local anchor = self:FindAnchor(timer.name, target.name, timer.duration);
    local timerSettings;
    if timer.module == self then
        timerSettings = self:FindTimerSettings(timer.name, anchor, target.name, timer.duration);
    else
        timerSettings = timer.module.GetTimerSettings and timer.module:GetTimerSettings(self, timer.name) or nil;
    end
    local isHidden = timer.module == self and self:Get("blocked-" .. target.name, string.lower(timer.name));
    local priority = timer.module == self and 0 or 10;
    local group = target.name == "Buffs" and self:Get("buffsName") or self:Get("debuffsName");
    local tID = TimerLib:NewTimer(timer, group, timer.module, timerSettings, priority, isHidden, anchor, 10, nil);
    timer.id = tID;
end

function listener:RemoveTimer(target, timer)
    TimerLib:DeleteTimer(timer.id, timer, (timer.module ~= self));
end

function listener:UpdateTimerData(timer)
    TimerLib:UpdateTimer(timer.id, timer);
end

listener:SetScript("OnTimerEnter", function(self, target, timer, id, frame)
    if timer then
        target = timer.target;
        local filter = target.name == "Buffs" and "HELPFUL" or "HARMFUL";
        Ash_GameTooltip:SetOwner(frame, "ANCHOR_RIGHT");
        Ash_GameTooltip:ClearLines();
        local time = GetTime();
        
        if timer.isTempEnchant then
            Ash_GameTooltip:SetInventoryItem("player", timer.isTempEnchant);
        else
            Ash_GameTooltip:SetUnitAura("player", timer.name, timer.rank, filter);
        end
        Ash_GameTooltip:AddLine(" ");
        
        Ash_GameTooltip:AddLine(string.format("|cff00ff00%s|r", timer.name));
        if timer.duration then
            Ash_GameTooltip:AddLine("Remaining: |cff6666ff" .. id:FormatTime(timer.duration - time + timer.time));
        end
        
        Ash_GameTooltip:AddLine(" ");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Announce") .. "|r to announce.");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Remove") .. "|r to remove.");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Block") .. "|r to block.");
        
        Ash_GameTooltip:Show();
    end
end)

listener:SetScript("OnTimerLeave", function(self, target, timer, id, frame)
    Ash_GameTooltip:Hide();
end)

listener:SetScript("OnTimerClick",function(self, target, timer, id, button)
    if timer then
        listener:ProcessClick("Timer", button, timer, id, timer.target.name);
    else
        TimerLib:DeleteTimer(id, timer, 1);
    end
end)
listener:SetClickAction("Timer", "Remove", function(timer, id)
    if timer.isTempEnchant then
        CancelItemTempEnchantment(timer.isTempEnchant - 15);
    else
        CancelUnitBuff("player", timer.name, timer.rank, timer.filter);
    end
end)
listener:SetClickAction("Timer", "Block", function(timer, _, target)
    if timer then
        local frame = StaticPopup_Show("PLAYERAURAS", timer.name)
        frame.data = timer.name;
        frame.data2 = target;
    end
end)
local subTimer, subID;
local subFunc = function(a)
    if a == "%s" then
        return subTimer.name;
    elseif a == "%d" then
        return subTimer.duration and subID:FormatTime(subTimer.duration - GetTime() + subTimer.time) or "";
    else
        return "";
    end
end
listener:SetClickAction("Timer", "Announce", function(timer, id, target)
    if listener:Get("isAnnouncing") then
        local prefix = timer.duration and "standardAnnounce-" or "noDurationAnnounce-";
        local subStr = listener:Get(prefix .. target);
        subTimer, subID = timer, id;
        local msg = string.gsub(subStr, "(%%%a)", subFunc);
        local loc = GetNumRaidMembers() > 0 and "RAID" or GetNumPartyMembers() > 0 and "PARTY" or "SAY";
        SendChatMessage(msg, loc);
    end
end)
StaticPopupDialogs["PLAYERAURAS"] = {
    text = "Are you sure you want to block |cff00ff00%s|r?  This can be undone from the options panel.",
    button1 = "Yes",
    button2 = "No",
    OnAccept = function(self, name, target) listener:Set("blocked-" .. target, string.lower(name), 1); end,
    whileDead = 1,
    hideOnEscape = 1,
    timeout = 0,
}

local filters = {
    ["Buffs"] = PlayerAuras:GetBuffsTarget(),
    ["Debuffs"] = PlayerAuras:GetDebuffsTarget(),
};

listener:AddDefaultSettings(defaultSettings);
listener:AddSettingsUpdateScript(function(self)
    if self:GetUserSet("keybindings") == nil then
        self:Set("keybindings", {
    		["Timer"] = {
    			["Announce"] = "1",
    			["Remove"] = "2",
    			["Block"] = "s-2",
    		},
    	});
    end
    if not self:GetUserSet("userAnchors-Buffs") then
        self:Set("userAnchors-Buffs", {
            ["PlayerAuras Anchor"] = {
                default = true,
                noDurLoc = true,
                timers = {},
                timerSettings = {},
            },
        });
    end
    if not self:GetUserSet("userAnchors-Debuffs") then
        self:Set("userAnchors-Debuffs", {
            ["PlayerAuras Anchor"] = {
                default = true,
                noDurLoc = true,
                timers = {},
                timerSettings = {},
            },
        });
    end
    if self:Get("enabled") and not AsheylaLib:InSimpleMode() then
        self:RegisterEvent("PLAYERAURAS_NEW_TIMER", self.MakeTimer);
        self:RegisterEvent("PLAYERAURAS_DONE_TIMER", self.RemoveTimer);
        self:RegisterEvent("PLAYERAURAS_UPDATE_TIMERDATA", self.UpdateTimerData);
        
        for name, target in pairs(filters) do
            for timer in target:GetTimers() do
                local anchor = self:FindAnchor(timer.name, name, timer.duration);
                local timerSettings = self:FindTimerSettings(timer.name, anchor, name, timer.duration);
                local isHidden = timer.module == self and self:Get("blocked-" .. name, string.lower(timer.name));
                local priority = timer.module == self and 0 or 10;
                TimerLib:UpdateTimerInfo(timer.id, timer, priority, isHidden, timerSettings);
                local group = name == "Buffs" and self:Get("buffsName") or self:Get("debuffsName");
                TimerLib:MoveTimer(timer.id, timer, group, anchor, 10, nil);
            end
        end
    else
        self:UnregisterEvent("PLAYERAURAS_NEW_TIMER");
        self:UnregisterEvent("PLAYERAURAS_DONE_TIMER");
        self:UnregisterEvent("PLAYERAURAS_UPDATE_TIMERDATA");
        TimerLib:DeleteAllTimers(self);
    end
end);

TimerLib:AddSettingsUpdateScript(function(self)
    if not self:GetUserSet("anchorSettings", "PlayerAuras Anchor") then
        self:Set("anchorSettings", "PlayerAuras Anchor", {
            groupSortMethod = "Alphabetical (A)",
        });
    end
    local default;
    for name, settings in pairs(PlayerAuras:Get("userAnchors-Buffs")) do
        if not self:Get("anchorSettings", name) then
            PlayerAuras:Set("userAnchors-Buffs", name, nil);
        elseif settings.default then
            default = name;
        end
    end
    if not default then
        PlayerAuras:Set("userAnchors-Buffs", "PlayerAuras Anchor", "default", true);
    end
    default = nil;
    for name, settings in pairs(PlayerAuras:Get("userAnchors-Debuffs")) do
        if not self:Get("anchorSettings", name) then
            PlayerAuras:Set("userAnchors-Debuffs", name, nil);
        elseif settings.default then
            default = name;
        end
    end
    if not default then
        PlayerAuras:Set("userAnchors-Debuffs", "PlayerAuras Anchor", "default", true);
    end
end);
