PmCa = PmCa or {}
base64 = base64 or {}

PmCa.name		   = 'PanicModeCombatAnalyzer'
PmCa.version	   = '1.2.0'
PmCa.versionDB	   = 4
PmCa.loaded	       = false
PmCa.author        = 'silentgecko, deevilius'
PmCa.savedVarsName = 'PMCAVars'

PmCa.variables = {
    data = {},
    metadata = {
        server = 'EU',
        language = 'de',
    }
}
PmCa.tempVars = {
    lastSave     = 0,
    lastSaveTimeStamp = 0,
    inFight      = false,
    lastDps      = 0,
    lastDpsCount = 0,
    trialRunning = false,
    trialId      = 0,
    timeStampOffsetToLead = 0,
}

---------Passing saved variables to the labels at initialize-------
function PmCa.Initialize(_, addonName)
    local self = PmCa

    if addonName ~= self.name then return end

    EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ADD_ON_LOADED)

    self.savedVariables = ZO_SavedVars:New(self.savedVarsName, self.versionDB, nil, self.variables)

    --save current server and language
    self.savedVariables.metadata = {
        server = GetWorldName(),
        language = GetCVar('language.2')
    }

    self.cleanUp()

    self.Damage:Initialize()

    -- death/alive/rezz
    EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_DEAD, self.onDeath)
    EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_ALIVE, self.onAlive)
    EVENT_MANAGER:RegisterForEvent(self.name, EVENT_RESURRECT_REQUEST, self.onRezz)

    --combat state
    EVENT_MANAGER:RegisterForEvent(self.name, EVENT_PLAYER_COMBAT_STATE, self.OnPlayerCombatState)

    -- damage event
    EVENT_MANAGER:RegisterForEvent(self.name, EVENT_COMBAT_EVENT, self.OnCombatEvent)
end


function PmCa.OnCombatEvent(_, result, isError, abilityName, _, _, _, sourceType, targetName, _, hitValue, _, _, _, _, _, abilityId)
    -- Ignore errors
    if (isError) then return end
    -- Pass damage event to handler
    PmCa.Damage:New(result, abilityName, sourceType, targetName, hitValue, abilityId)
end

function PmCa:getOffset(offset, finished)
    local self = PmCa
    self.debug('PmCa Synced Offset from lead:', offset)
    self.tempVars.timeStampOffsetToLead = offset
end

-- cleanup
function PmCa.cleanUp()
    local self      = PmCa
    local savedVars = self.savedVariables.data
    local currentTs = GetTimeStamp()
    local limitTs   = currentTs - 604800 -- one week in seconds

    for ts, data in pairs(savedVars) do
        if ts <= limitTs then
            self.savedVariables.data[ts] = nil
        end
    end
end

-- fight status
function PmCa.OnPlayerCombatState(_, inCombat)
    local self       = PmCa
    local timeStamp  = GetTimeStamp() + self.tempVars.timeStampOffsetToLead
    local data       = self.savedVariables.data or {}

    data[timeStamp]          = data[timeStamp] or {}
    data[timeStamp]['event'] = data[timeStamp]['event'] or {}
    table.insert(data[timeStamp]['event'], {combat = inCombat})

    -- add group and trial to event
    data[timeStamp]['trial'] = self.getTrial()
    data[timeStamp]['group'] = self.getGroupEnc()
    self.savedVariables.data[timeStamp] = data[timeStamp]
end

-- get current trial
function PmCa.getTrial()
    local self         = PmCa
    local currentRaid  = GetCurrentParticipatingRaidId() or 0
    return currentRaid
end

-- player death / revive
function PmCa.onDeath(event)
    local self       = PmCa
    local timeStamp  = GetTimeStamp() + self.tempVars.timeStampOffsetToLead
    local data       = self.savedVariables.data or {}
    data[timeStamp] = data[timeStamp] or {}
    if (event == EVENT_PLAYER_DEAD) then -- player died
        data[timeStamp]['event'] = data[timeStamp]['event'] or {}
        table.insert(data[timeStamp]['event'], {death = true})
    else -- player lives again
        data[timeStamp]['event'] = data[timeStamp]['event'] or {}
        table.insert(data[timeStamp]['event'], {revive = true})
    end

    -- add group and trial to event
    data[timeStamp]['trial'] = self.getTrial()
    data[timeStamp]['group'] = self.getGroupEnc()

    self.savedVariables.data[timeStamp] = data[timeStamp]
end

-- player alive
function PmCa.onAlive(event)
    local self       = PmCa
    local timeStamp  = GetTimeStamp() + self.tempVars.timeStampOffsetToLead
    local data       = self.savedVariables.data or {}

    data[timeStamp]          = data[timeStamp] or {}
    data[timeStamp]['event'] = data[timeStamp]['event'] or {}
    table.insert(data[timeStamp]['event'], {alive = true})

    -- add group and trial to event
    data[timeStamp]['trial'] = self.getTrial()
    data[timeStamp]['group'] = self.getGroupEnc()

    self.savedVariables.data[timeStamp] = data[timeStamp]
end

-- player rezz
function PmCa.onRezz(event, requesterCharacterName, timeLeftToAccept)
    local self       = PmCa
    local timeStamp  = GetTimeStamp() + self.tempVars.timeStampOffsetToLead
    local data       = self.savedVariables.data or {}

    data[timeStamp]          = data[timeStamp] or {}
    data[timeStamp]['event'] = data[timeStamp]['event'] or {}

    table.insert(data[timeStamp]['event'], {rezz = zo_strformat("<<!aC:1>>", requesterCharacterName)})

    -- add group and trial to event
    if self.getTrial() > 0 then
        data[timeStamp]['trial'] = self.getTrial()
    end
    if GetGroupSize() > 0 then
        data[timeStamp]['group'] = self.getGroupEnc()
    end

    self.savedVariables.data[timeStamp] = data[timeStamp]
end


-- group change
function PmCa.getGroupEnc()
    local self       = PmCa
    local group      = self.getGroup()
    local groupEnc   = ''
    local groupStr   = ''

    --sort group
    local groupSort = function(char1, char2) return char1.name < char2.name end
    table.sort(group, groupSort)

    -- encode group
    for key,charName in pairs(group) do --actualcode
        groupStr = groupStr .. "," .. charName.name
    end
    groupStr = string.sub(groupStr, 2);

    groupEnc = base64.enc(groupStr)

    return groupEnc
end

-- get group
function PmCa.getGroup()
    local self      = PmCa
    local groupSize = GetGroupSize()
    local group     = {}

    -- iterate over group
    if groupSize > 0 then
        for i = 1, groupSize do
            local unitTag = GetGroupUnitTagByIndex(i)
            if (DoesUnitExist(unitTag)) then
                local charName = zo_strformat("<<!aC:1>>", GetUnitName(unitTag))
                local charTable = {
                    name = charName
                }
                table.insert(group, charTable)
            end
        end
    end

    return group
end

-- debug func
function PmCa.debug(message, data)
    d('PM CA Debug:')
    d(message, data)
end

---------Callbacks-----
local LGS = LibStub("LibGroupSocket")
local SyncTimeStampHandler = LGS:GetHandler(LGS.MESSAGE_TYPE_SYNC_TIMESTAMP)
SyncTimeStampHandler:RegisterForFinishedSyncOffset(function(offset, syncFinished)
    PmCa:getOffset(offset, syncFinished)
end)

---------Events-------
EVENT_MANAGER:RegisterForEvent(PmCa.name, EVENT_ADD_ON_LOADED, PmCa.Initialize)