LeoGM = {}
LeoGM.name = "LeoGuildManager"
LeoGM.displayName = "Leo's Guild Manager"
LeoGM.version = "0.9.3"
LeoGM.chatPrefix = "|c39B027" .. LeoGM.name .. "|r: "
LeoGM.panelList = { "Rules", "Purge" }
LeoGM.members = {}
LeoGM.guilds = {}
LeoGM.isScanning = false
LeoGM.salesEvents = {}
LeoGM.depositsEvents = {}
LeoGM.numEvents = {}

function LeoGM.formatNumber(amount)
    if amount == nil then return nil; end
    if type(amount) == "string" then amount = tonumber( amount ) end
    if type(amount) ~= "number" then return amount; end
    if amount < 1000 then return amount; end
    return FormatIntegerWithDigitGrouping( amount, GetString( SI_DIGIT_GROUP_SEPARATOR ) )
end

function LeoGM.GetGuilds(gName)
    guilds = {}
    if GetNumGuilds() > 0 then
        for guild = 1, GetNumGuilds() do
            local guildId = GetGuildId(guild)
            local guildName = GetGuildName(guildId)
            if(not guildName or (guildName):len() < 1) then
                guildName = "Guild " .. guildId
            end
            if gName ~= nil and gName == guildName then
                return guildId
            end
            guilds[guildId] = guildName
        end
    end
    return guilds
end

function LeoGM.GetGuildMembers(guildId)

    LeoGM.members = {}
    local numGuildMembers = GetNumGuildMembers(guildId)
    for guildMemberIndex = 1, numGuildMembers do
        local displayName, note, rankIndex, status, secsSinceLogoff = GetGuildMemberInfo(guildId, guildMemberIndex)
        local rankId = GetGuildRankId(guildId, rankIndex)
        local rankName = GetGuildRankCustomName(guildId, rankIndex)
        table.insert(LeoGM.members, {
            name = displayName,
            rankIndex = rankIndex,
            rankId = rankId,
            rankName = rankName,
            online = secsSinceLogoff,
            deposits = 0,
            taxes = 0,
            sales = 0
        })
    end
end

function LeoGM.AddSale(memberName, value)
    for i = 1, #LeoGM.members do
        if LeoGM.members[i].name == memberName then
            LeoGM.members[i].sales = LeoGM.members[i].sales + value
            return
        end
    end
end

function LeoGM.AddDeposit(memberName, value)
    for i = 1, #LeoGM.members do
        if LeoGM.members[i].name == memberName then
            LeoGM.members[i].deposits = LeoGM.members[i].deposits + value
            return
        end
    end
end

function LeoGM.AddTax(memberName, value)
    for i = 1, #LeoGM.members do
        if LeoGM.members[i].name == memberName then
            LeoGM.members[i].taxes = LeoGM.members[i].taxes + value
            return
        end
    end
end

function LeoGM.IsNewestFirst(guildID)
    local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_STORE)
    local _, secsSinceFirst, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_STORE, 1)
    local _, secsSinceLast, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_STORE, numEvents)
    return (secsSinceFirst < secsSinceLast)
end

function LeoGM.BuildSalesHistory(guildId, scanSince)

    if LeoGM.isScanning then return nil end

    LeoGMWindowPurgePanelListButton:SetEnabled(false)
    LeoGMWindowPurgePanelLoadingIcon:SetHidden(false)
    LeoGMWindowPurgePanelLoadingIcon.animation:PlayForward()

    LeoGM.requestTimestamp = GetTimeStamp()
    RequestGuildHistoryCategoryNewest(guildId, GUILD_HISTORY_STORE)
    zo_callLater(function() LeoGM.ScanOlderSales(guildId, scanSince) end, 2000)
end

function LeoGM.ProcessSales(guildNum, lastSaleTime, startIndex, endIndex, loopIncrement)

    local addedEvents = 0
    local guildID = GetGuildId(guildNum)
    local guildName = GetGuildName(guildID)

    local guildMemberInfo = {}
    for i = 1, GetNumGuildMembers(guildID) do
        local guildMemInfo, _, _, _, _ = GetGuildMemberInfo(guildID, i)
        guildMemberInfo[string.lower(guildMemInfo)] = true
    end

    for i = startIndex, endIndex, loopIncrement do
        local theEvent = {}
        theEvent.eventType, theEvent.secsSince, theEvent.seller, theEvent.buyer,
        theEvent.quant, theEvent.itemName, theEvent.salePrice = GetGuildEventInfo(guildID, GUILD_HISTORY_STORE, i)
        theEvent.guild = guildName
        theEvent.saleTime = GetTimeStamp() - theEvent.secsSince

        if theEvent.eventType == GUILD_EVENT_ITEM_SOLD then

            theEvent.kioskSale = (guildMemberInfo[string.lower(theEvent.buyer)] == nil)
            theEvent.id = Id64ToString(GetGuildEventId(guildID, GUILD_HISTORY_STORE, i))

            addedEvents = addedEvents + 1
            table.insert(LeoGM.salesEvents, theEvent)

            if addedEvents > 100 then
                startIndex = i + loopIncrement
                break
            end
        end
    end

    if addedEvents <= 100 then
        startIndex = 0
        endIndex = 0
        loopIncrement = 0
    end

    return startIndex, endIndex, loopIncrement

end

function LeoGM.DoSalesScan(guildNum, checkOlder, scanSince, startIndex, endIndex, loopIncrement)

    local guildID = GetGuildId(guildNum)
    local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_STORE)
    local guildName = GetGuildName(guildID)

    if loopIncrement ~= nil and loopIncrement ~= 0 then
        startIndex, endIndex, loopIncrement = LeoGM.ProcessSales(guildNum, scanSince, startIndex, endIndex, loopIncrement)
    else
        local prevEvents = 0

        if LeoGM.numEvents[guildName] ~= nil then prevEvents = LeoGM.numEvents[guildName] end

        if numEvents > prevEvents then

            startIndex = prevEvents + 1
            endIndex = numEvents
            loopIncrement = 1

            if LeoGM.IsNewestFirst(guildID) then
                startIndex = numEvents - prevEvents
                endIndex = 1
                loopIncrement = -1
            end

            startIndex, endIndex, loopIncrement = LeoGM.ProcessSales(guildNum, scanSince, startIndex, endIndex, loopIncrement)
        else
            loopIncrement = 0;
        end
    end

    if loopIncrement ~= 0 then
        zo_callLater(function() LeoGM.DoSalesScan(guildNum, checkOlder, scanSince, startIndex, endIndex, loopIncrement) end, 50)
        return
    end

    LeoGM.numEvents[guildName] = numEvents

    d('|cFFFF00Finished adding ' .. numEvents .. ' sales events from ' .. guildName .. '.|r')

    LeoGM.isScanning = false
    LeoGMWindowPurgePanelListButton:SetEnabled(true)
    LeoGMWindowPurgePanelLoadingIcon:SetHidden(true)
    LeoGMWindowPurgePanelLoadingIcon.animation:Stop()
    LeoGM:PostScan()
end

function LeoGM.ScanOlderSales(guildNum, scanSince, oldNumEvents, badLoads)
    local guildID = GetGuildId(guildNum)
    local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_STORE)
    local _, secsSinceFirst, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_STORE, 1)
    local _, secsSinceLast, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_STORE, numEvents)
    local timeToUse = GetTimeStamp() - math.max(secsSinceFirst, secsSinceLast)

    badLoads = badLoads or 0
    oldNumEvents = oldNumEvents or 0

    if numEvents == 0 then
        return nil
    end
    if numEvents > oldNumEvents then badLoads = 0 else badLoads = badLoads + 1 end

    if DoesGuildHistoryCategoryHaveMoreEvents(guildID, GUILD_HISTORY_STORE) and badLoads < 10 and timeToUse > scanSince then
        RequestGuildHistoryCategoryOlder(guildID, GUILD_HISTORY_STORE)
        zo_callLater(function() LeoGM.ScanOlderSales(guildNum, scanSince, numEvents, badLoads) end, 1500)
    else zo_callLater(function() LeoGM.DoSalesScan(guildNum, true, scanSince) end, 1500) end
end

function LeoGM.BuildDepositsHistory(guildId, scanSince)

    if LeoGM.isScanning then return nil end

    LeoGMWindowPurgePanelListButton:SetEnabled(false)
    LeoGMWindowPurgePanelLoadingIcon:SetHidden(false)
    LeoGMWindowPurgePanelLoadingIcon.animation:PlayForward()

    if #LeoGM.depositsEvents == 0 then
        LeoGM.requestTimestamp = GetTimeStamp()
        RequestGuildHistoryCategoryNewest(guildId, GUILD_HISTORY_BANK)
        zo_callLater(function() LeoGM.ScanOlderDeposits(guildId, scanSince) end, 2000)
    else
        LeoGM:PostScan()
        LeoGMWindowPurgePanelListButton:SetEnabled(true)
        LeoGMWindowPurgePanelLoadingIcon:SetHidden(true)
        LeoGMWindowPurgePanelLoadingIcon.animation:Stop()
    end
end

function LeoGM.ProcessDeposits(guildNum, lastSaleTime, startIndex, endIndex, loopIncrement)

    local addedEvents = 0
    local guildID = GetGuildId(guildNum)
    local guildName = GetGuildName(guildID)

    local guildMemberInfo = {}
    for i = 1, GetNumGuildMembers(guildID) do
        local guildMemInfo, _, _, _, _ = GetGuildMemberInfo(guildID, i)
        guildMemberInfo[string.lower(guildMemInfo)] = true
    end

    for i = startIndex, endIndex, loopIncrement do
        local theEvent = {}
        theEvent.eventType, theEvent.secsSince, theEvent.seller, theEvent.value = GetGuildEventInfo(guildID, GUILD_HISTORY_BANK, i)
        theEvent.guild = guildName
        theEvent.saleTime = GetTimeStamp() - theEvent.secsSince

        if theEvent.eventType == GUILD_EVENT_BANKGOLD_ADDED then

            theEvent.id = Id64ToString(GetGuildEventId(guildID, GUILD_HISTORY_BANK, i))

            addedEvents = addedEvents + 1
            table.insert(LeoGM.depositsEvents, theEvent)

            if addedEvents > 100 then
                startIndex = i + loopIncrement
                break
            end
        end
    end

    if addedEvents <= 100 then
        startIndex = 0
        endIndex = 0
        loopIncrement = 0
    end

    return startIndex, endIndex, loopIncrement

end

function LeoGM.DoDepositsScan(guildNum, checkOlder, scanSince, startIndex, endIndex, loopIncrement)

    local guildID = GetGuildId(guildNum)
    local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_BANK)
    local guildName = GetGuildName(guildID)

    if loopIncrement ~= nil and loopIncrement ~= 0 then
        startIndex, endIndex, loopIncrement = LeoGM.ProcessDeposits(guildNum, scanSince, startIndex, endIndex, loopIncrement)
    else
        local prevEvents = 0

        if LeoGM.numEvents[guildName] ~= nil then prevEvents = LeoGM.numEvents[guildName] end

        if numEvents > prevEvents then

            startIndex = prevEvents + 1
            endIndex = numEvents
            loopIncrement = 1

            if LeoGM.IsNewestFirst(guildID) then
                startIndex = numEvents - prevEvents
                endIndex = 1
                loopIncrement = -1
            end

            startIndex, endIndex, loopIncrement = LeoGM.ProcessDeposits(guildNum, scanSince, startIndex, endIndex, loopIncrement)
        else
            loopIncrement = 0;
        end
    end

    if loopIncrement ~= 0 then
        zo_callLater(function() LeoGM.DoDepositsScan(guildNum, checkOlder, scanSince, startIndex, endIndex, loopIncrement) end, 50)
        return
    end

    LeoGM.numEvents[guildName] = numEvents

    d('|cFFFF00Finished adding ' .. numEvents .. ' deposit events from ' .. guildName .. '.|r')

    LeoGM.isScanning = false
    LeoGMWindowPurgePanelListButton:SetEnabled(true)
    LeoGMWindowPurgePanelLoadingIcon:SetHidden(true)
    LeoGMWindowPurgePanelLoadingIcon.animation:Stop()
    LeoGM.PostScan()
    --LeoGM.BuildSalesHistory(guildNum, scanSince)
end

function LeoGM.ScanOlderDeposits(guildNum, scanSince, oldNumEvents, badLoads)
    local guildID = GetGuildId(guildNum)
    local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_BANK)
    local _, secsSinceFirst, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_BANK, 1)
    local _, secsSinceLast, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_BANK, numEvents)
    local timeToUse = GetTimeStamp() - math.max(secsSinceFirst, secsSinceLast)

    badLoads = badLoads or 0
    oldNumEvents = oldNumEvents or 0

    if numEvents == 0 then
        return nil
    end
    if numEvents > oldNumEvents then badLoads = 0 else badLoads = badLoads + 1 end

    if DoesGuildHistoryCategoryHaveMoreEvents(guildID, GUILD_HISTORY_BANK) and badLoads < 10 and timeToUse > scanSince then
        RequestGuildHistoryCategoryOlder(guildID, GUILD_HISTORY_BANK)
        zo_callLater(function() LeoGM.ScanOlderDeposits(guildNum, scanSince, numEvents, badLoads) end, 1500)
    else zo_callLater(function() LeoGM.DoDepositsScan(guildNum, true, scanSince) end, 1500) end
end

function LeoGM.PostScan()
    for _, event in pairs(LeoGM.depositsEvents) do
        for _, member in pairs(LeoGM.members) do
            if event.seller == member.name then
                member.deposits = member.deposits + event.value
                break
            end
        end
    end
    if MasterMerchant then
        for sn, sellerData in pairs(MasterMerchant.guildSales[LeoGM.savedVariables.selectedGuild].sellers) do
            for _, member in pairs(LeoGM.members) do
                if sn == member.name and sellerData.sales[5] then
                    member.sales = member.sales + sellerData.sales[5]
                end
            end
        end
    end
    --[[
    for _, event in pairs(LeoGM.salesEvents) do
        for _, member in pairs(LeoGM.members) do
            if event.seller == member.name then
                member.sales = member.sales + event.salePrice
                break
            end
        end
    end
    ]]
    LeoGM.memberScroll:RefreshData()
end

function LeoGM.Initialize()
    LeoGM.savedVariables = ZO_SavedVars:NewAccountWide("LeoGMSavedVariables", 1)

    if not LeoGM.savedVariables.rules then
        LeoGM.savedVariables.rules = {}
    end

    local LibFeedback = LibStub:GetLibrary("LibFeedback")
    local showButton, feedbackWindow = LibFeedback:initializeFeedbackWindow(LeoGM,
        LeoGM.name,LeoGMWindow, "@LeandroSilva",
        {TOPRIGHT, LeoGMWindow, TOPRIGHT,-50,3},
        {0,1000,10000,"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y9KM4PZU2UZ6A"},
        "If you found a bug, have a request or a suggestion, or simply wish to donate, send a mail.")
    LeoGM.feedback = feedbackWindow

    LeoGM.guilds = LeoGM.GetGuilds()

    LeoGM.InitializeUI()
    LeoGM.RestorePosition()

    SLASH_COMMANDS["/rr"] = function(cmd)
        ReloadUI()
    end

    SLASH_COMMANDS["/leogm"] = function(cmd)
        LeoGM:ShowUI()
    end
end

function LeoGM.OnAddOnLoaded(event, addonName)
    if addonName == LeoGM.name then
        EVENT_MANAGER:UnregisterForEvent(LeoGM.Name, EVENT_ADD_ON_LOADED)
        LeoGM.Initialize()
        --        d(LeoGM.name .. " started.")
    end
end

EVENT_MANAGER:RegisterForEvent(LeoGM.name, EVENT_ADD_ON_LOADED, LeoGM.OnAddOnLoaded)