PlayerAuras = AsheylaLib:NewModule("PlayerAuras", "KBLib");

local defaultSettings = {
    enabled = true,
    blizzBuffs = false,
    noDuration = {},
};
PlayerAuras:AddDefaultSettings(defaultSettings);

local targetModule = PlayerAurasTarget;
local timerModule = PlayerAurasTimer;

local buffsTarget = targetModule:MakeBuffsTable(PlayerAuras);
local debuffsTarget = targetModule:MakeDebuffsTable(PlayerAuras);

function PlayerAuras:GetBuffsTarget()
    return buffsTarget;
end

function PlayerAuras:GetDebuffsTarget()
    return debuffsTarget;
end

local TIME_REMAINING = "PLAYERAURAS_TIME_REMAINING";

local filters = {
    ["HELPFUL"] = buffsTarget,
    ["HARMFUL"] = debuffsTarget,
};

local internalFrame = CreateFrame("Frame");
internalFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
internalFrame:SetScript("OnEvent", function(self, event, ...)
    PlayerAuras[event](PlayerAuras, ...);
end);

local updateFunc = function(self, elapsed)
    local time = GetTime();
    local numTimers = 0;
    for filter, target in pairs(filters) do
        for timer in target:GetTimers() do
            if timer.duration then
                if time >= timer.time + timer.duration then
                    target:RemoveTimer(timer);
                else
                    timer.announced = timer.announced or floor(timer.duration);
                    local remaining = timer.duration - time + timer.time;
                    if remaining <= timer.announced - 1 then
                        timer.announced = timer.announced - 1;
                        AsheylaLib:CallEvent(TIME_REMAINING, timer, timer.announced);
                    end
                end
            end
        end
        numTimers = numTimers + #target.timers;
    end
    
    if numTimers == 0 then
        self:SetScript("OnUpdate", nil);
    end
end;

function PlayerAuras:UNIT_AURA(unit)
    if not UnitIsUnit(unit, "player") then return; end
    
    for filter, target in pairs(filters) do
        for timer in target:GetTimers() do
            if not timer.isTempEnchant then 
                timer.validated = false;
            end
        end
        
        local i = 1;
        local name, rank, texture, count, debuffType, duration, endTime, isMine = UnitAura(unit, i, filter);
        while name do
            if duration == 0 or self:Get("noDuration", string.lower(name)) then duration = nil; end
            local adding = true;
            for timer in target:GetTimers() do
                if timer.name == name then
                    timer.validated = true;
                    adding = false;
                    timer:UpdateTimerData(duration, endTime, count);
                    break;
                end
            end
            
            if adding then
                local timer = timerModule:NewTimer(self, name, rank, texture, count, duration, endTime, filter);
                target:AddTimer(timer);
                internalFrame:SetScript("OnUpdate", updateFunc);
            end
            
            i = i + 1;
            name, rank, texture, count, debuffType, duration, endTime, isMine = UnitAura(unit, i, filter);
        end
        
        for timer in target:GetTimers() do
            if not (timer.validated or timer.isTempEnchant) then
                target:RemoveTimer(timer);
            end
        end
    end
end

local scanningFrame = CreateFrame("GameTooltip", "PlayerAurasScanningFrame", nil, "GameTooltipTemplate");
local function getEnchantName(id)
	scanningFrame:SetOwner(UIParent,"ANCHOR_NONE")
	scanningFrame:SetInventoryItem("player", id);
    for i = 1, scanningFrame:NumLines() do
        local text = getglobal("PlayerAurasScanningFrameTextLeft"..i):GetText();
        local name = string.match(text, "(.+) %(.*%d+.*%)$");
        if name then return name; end
    end
end

local function checkWeapEnchant(has, expir, charges, timer, num, time)
    if has then
        local timeLeft = expir / 1000;
        if timer then
            timer:UpdateTimerData(timer.duration, time + timeLeft, charges);
        else
            --DoTimer:Print("add: ", num);
            local itemName = getEnchantName(num) or GetItemInfo(GetInventoryItemLink("player", num));
            if itemName then
                local duration = not PlayerAuras:Get("noDuration", string.lower(itemName)) and timeLeft or nil;
                local texture = GetInventoryItemTexture("player", num);
                timer = timerModule:NewTimer(PlayerAuras, itemName, nil, texture, charges, duration, time + timeLeft, "HELPFUL");
                timer.isTempEnchant = num;
                buffsTarget:AddTimer(timer);
            end
        end
    elseif timer then
        --DoTimer:Print("delete: ", num);
        buffsTarget:RemoveTimer(timer);
        timer = false;
    end
    
    return timer;
end

local tempEnchantFrame = CreateFrame("Frame");
tempEnchantFrame.elapsed = 0;
local mainHandRunning, offHandRunning = false, false;
local function tempEnchantUpdate(self, elapsed)
    self.elapsed = self.elapsed + elapsed;
    if self.elapsed >= .1 then
        self.elapsed = 0;
        local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();
        local time = GetTime();
        mainHandRunning = checkWeapEnchant(hasMainHandEnchant, mainHandExpiration, mainHandCharges, mainHandRunning, 16, time);
        offHandRunning = checkWeapEnchant(hasOffHandEnchant, offHandExpiration, offHandCharges, offHandRunning, 17, time);
    end
end

function PlayerAuras:Commands()
    local loaded = LoadAddOn("DoTimer_Options");
    if loaded then
        GUILib:ShowPanel("PlayerAuras", "main");
    end
end
PlayerAuras:MakeSlashCmd("/playerauras", "/pa");

local blizzHidden = false;
local hasBeenEnabled = false;
function PlayerAuras:PLAYER_ENTERING_WORLD()
    internalFrame:UnregisterEvent("PLAYER_ENTERING_WORLD");
    self:AddSettingsUpdateScript(function(self)
        if AsheylaLib:InSimpleMode() then
            if not BuffFrame:IsShown() and not hasBeenEnabled then
                blizzHidden = true;
            end
            if blizzHidden then
                BuffFrame:Hide();
                TemporaryEnchantFrame:Hide();
            else
                BuffFrame:Show();
                TemporaryEnchantFrame:Show();
            end
        else
            if self:Get("blizzBuffs") then
        		BuffFrame:Show();
        		TemporaryEnchantFrame:Show();
        	else
        		BuffFrame:Hide();
        		TemporaryEnchantFrame:Hide();
            end
        end
        
        if self:Get("enabled") and not AsheylaLib:InSimpleMode() then
            hasBeenEnabled = true;
            internalFrame:RegisterEvent("UNIT_AURA");
            for filter, target in pairs(filters) do
                for timer in target:GetTimers() do
                    if self:Get("noDuration", string.lower(timer.name)) then
                        timer:UpdateTimerData(nil, nil, timer.stack);
                    else
                        if timer.isTempEnchant then
                            local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();
                            if timer.isTempEnchant == 16 then
                                timer:UpdateTimerData(mainHandExpiration / 1000, GetTime() + (mainHandExpiration / 1000), mainHandCharges);
                            else
                                timer:UpdateTimerData(offHandExpiration / 1000, GetTime() + (offHandExpiration / 1000), offHandCharges);
                            end
                        else
                            local _, _, _, _, _, duration, endTime = UnitAura("player", timer.name, timer.rank, filter);
                            timer:UpdateTimerData(duration > 0 and duration or nil, endTime, timer.stack);
                        end
                    end
                end
            end
            self:UNIT_AURA("player");
            tempEnchantFrame:SetScript("OnUpdate", tempEnchantUpdate);
        else
            internalFrame:UnregisterEvent("UNIT_AURA");
            tempEnchantFrame:SetScript("OnUpdate", nil);
        end
    end);
    self:UpdateSettings();
end
