

local Details = _G.Details
local textAlpha = 0.9
local AceLocale = LibStub ("AceLocale-3.0")
local L = AceLocale:GetLocale ( "Details" )

local on_deathrecap_line_enter = function (self)
	if (self.spellid) then
		GameTooltip:SetOwner (self, "ANCHOR_RIGHT")
		Details:GameTooltipSetSpellByID (self.spellid)
		self:SetBackdropColor (.3, .3, .3, .2)
		GameTooltip:Show()
		self.backgroundTextureOverlay:Show()
		self.timeAt:SetAlpha (1)
		self.sourceName:SetAlpha (1)
		self.amount:SetAlpha (1)
		self.lifePercent:SetAlpha (1)
	end
end

local on_deathrecap_line_leave = function (self)
	GameTooltip:Hide()
	self:SetBackdropColor (.3, .3, .3, 0)
	self.backgroundTextureOverlay:Hide()
	self.timeAt:SetAlpha (textAlpha)
	self.sourceName:SetAlpha (textAlpha)
	self.amount:SetAlpha (textAlpha)
	self.lifePercent:SetAlpha (textAlpha)
end

local create_deathrecap_line = function (parent, n)
	local line = CreateFrame ("frame", "DetailsDeathRecapLine" .. n, parent, "BackdropTemplate")
	line:SetPoint ("topleft", parent, "topleft", 10, (-24 * n) - 17)
	line:SetPoint ("topright", parent, "topright", -10, (-24 * n) - 17)
	line:SetScript ("OnEnter", on_deathrecap_line_enter)
	line:SetScript ("OnLeave", on_deathrecap_line_leave)
	
	line:SetSize (300, 21)

	local timeAt = line:CreateFontString (nil, "overlay", "GameFontNormal")
	local backgroundTexture = line:CreateTexture (nil, "border")
	local backgroundTextureOverlay = line:CreateTexture (nil, "artwork")
	local spellIcon = line:CreateTexture (nil, "overlay")
	local spellIconBorder = line:CreateTexture (nil, "overlay")
	spellIcon:SetDrawLayer ("overlay", 1)
	spellIconBorder:SetDrawLayer ("overlay", 2)
	local sourceName = line:CreateFontString (nil, "overlay", "GameFontNormal")
	local amount = line:CreateFontString (nil, "overlay", "GameFontNormal")
	local lifePercent = line:CreateFontString (nil, "overlay", "GameFontNormal")
	local lifeStatusBar = line:CreateTexture(nil, "border", nil, -3)
	
	--grave icon
	local graveIcon = line:CreateTexture (nil, "overlay")
	graveIcon:SetTexture ([[Interface\MINIMAP\POIIcons]])
	graveIcon:SetTexCoord (146/256, 160/256, 0/512, 18/512)
	graveIcon:SetPoint ("left", line, "left", 11, 0)
	graveIcon:SetSize (14, 18)
	
	--spell icon
	spellIcon:SetSize (19, 19)
	spellIconBorder:SetTexture ([[Interface\ENCOUNTERJOURNAL\LootTab]])
	spellIconBorder:SetTexCoord (6/256, 38/256, 49/128, 81/128)
	spellIconBorder:SetSize (20, 20)
	spellIconBorder:SetPoint ("topleft", spellIcon, "topleft", 0, 0)

	--locations
	timeAt:SetPoint ("left", line, "left", 2, 0)
	spellIcon:SetPoint ("left", line, "left", 50, 0)
	sourceName:SetPoint ("left", line, "left", 82, 0)
	amount:SetPoint ("left", line, "left", 240, 0)
	lifePercent:SetPoint ("left", line, "left", 320, 0)
	
	--text colors
	Details.gump:SetFontColor (amount, "red")
	Details.gump:SetFontColor (timeAt, "gray")
	Details.gump:SetFontColor (sourceName, "yellow")
	
	Details.gump:SetFontSize (sourceName, 10)

	--text alpha
	timeAt:SetAlpha (textAlpha)
	sourceName:SetAlpha (textAlpha)
	amount:SetAlpha (textAlpha)
	lifePercent:SetAlpha (textAlpha)
	
	--text setup
	amount:SetWidth (85)
	amount:SetJustifyH ("right")
	lifePercent:SetWidth (42)
	lifePercent:SetJustifyH ("right")
	
	--life statusbar
	lifeStatusBar:SetPoint("topleft", line, "topleft")
	lifeStatusBar:SetPoint("bottomleft", line, "bottomleft")
	lifeStatusBar:SetColorTexture(0.5, 0.5, 0.5, 0.4)

	backgroundTexture:SetTexture ([[Interface\AddOns\Details\images\deathrecap_background]])
	backgroundTexture:SetTexCoord (0, 1, 0, 1)
	backgroundTexture:SetVertexColor (.1, .1, .1, .3)
	
	--top border
	local TopFader = line:CreateTexture (nil, "border")
	TopFader:SetTexture ([[Interface\AddOns\Details\images\deathrecap_background_top]])
	TopFader:SetTexCoord (0, 1, 0, 1)
	TopFader:SetVertexColor (.1, .1, .1, .3)
	TopFader:SetPoint ("bottomleft", backgroundTexture, "topleft", 0, -0)
	TopFader:SetPoint ("bottomright", backgroundTexture, "topright", 0, -0)
	TopFader:SetHeight (32)
	TopFader:Hide()
	line.TopFader = TopFader
	
	if (n == 10) then
		--bottom fader
		local backgroundTexture2 = line:CreateTexture (nil, "border")
		backgroundTexture2:SetTexture ([[Interface\AddOns\Details\images\deathrecap_background_bottom]])
		backgroundTexture2:SetTexCoord (0, 1, 0, 1)
		backgroundTexture2:SetVertexColor (.1, .1, .1, .3)	
		backgroundTexture2:SetPoint ("topleft", backgroundTexture, "bottomleft", 0, 0)
		backgroundTexture2:SetPoint ("topright", backgroundTexture, "bottomright", 0, 0)
		backgroundTexture2:SetHeight (32)

		Details.gump:SetFontSize (amount, 14)
		Details.gump:SetFontSize (lifePercent, 14)
		backgroundTexture:SetVertexColor (.2, .1, .1, .3)
	end
	
	backgroundTexture:SetPoint ("topleft", 0, 1)
	backgroundTexture:SetPoint ("bottomright", 0, -1)
	backgroundTexture:SetDesaturated (true)
	backgroundTextureOverlay:SetTexture ([[Interface\AdventureMap\AdventureMap]])
	backgroundTextureOverlay:SetTexCoord (460/1024, 659/1024, 330/1024, 350/1024)
	backgroundTextureOverlay:SetAllPoints()
	backgroundTextureOverlay:SetDesaturated (true)
	backgroundTextureOverlay:SetAlpha (0.5)
	backgroundTextureOverlay:Hide()
	
	line.timeAt = timeAt
	line.spellIcon = spellIcon
	line.sourceName = sourceName
	line.amount = amount
	line.lifePercent = lifePercent
	line.backgroundTexture = backgroundTexture
	line.backgroundTextureOverlay = backgroundTextureOverlay
	line.graveIcon = graveIcon
	line.lifeStatusBar = lifeStatusBar
	
	if (n == 10) then
		graveIcon:Show()
		line.timeAt:Hide()
	else
		graveIcon:Hide()
	end
	
	return line
end

local OpenDetailsDeathRecapAtSegment = function (segment)
	Details.OpenDetailsDeathRecap (segment, RecapID)
end

function Details.BuildDeathTableFromRecap (recapID)
	local events = DeathRecap_GetEvents (recapID)
	
	--check if it is a valid recap
	if (not events or #events <= 0) then
		DeathRecapFrame.Unavailable:Show()
		return
	end
	
	--build an death log using details format
	ArtificialDeathLog = {
		{}, --deathlog events
		(events [1] and events [1].timestamp) or (DeathRecapFrame and DeathRecapFrame.DeathTimeStamp) or 0, --time of death
		UnitName ("player"),
		select (2, UnitClass ("player")),
		UnitHealthMax ("player"),
		"0m 0s", --formated fight time
		["dead"] = true,
		["last_cooldown"] = false,
		["dead_at"] = 0,
		n = 1
	}

	for i = 1, #events do
		local evtData = events [i]
		local spellId, spellName, texture = DeathRecapFrame_GetEventInfo ( evtData )

		local ev = {
			true,
			spellId or 0,
			evtData.amount or 0,
			evtData.timestamp or 0, --?
			evtData.currentHP or 0,
			evtData.sourceName or "--x--x--",
			evtData.absorbed or 0,
			evtData.school or 0,
			false,
			evtData.overkill,
			not spellId and {spellId, spellName, texture},
		}
		
		tinsert (ArtificialDeathLog[1], ev)
		ArtificialDeathLog.n = ArtificialDeathLog.n + 1
	end
	
	return ArtificialDeathLog
end

function Details.GetDeathRecapFromChat()
	local chat1 = ChatFrame1
	local recapIDFromChat
	if (chat1) then
		local numLines = chat1:GetNumMessages()
		for i = numLines, 1, -1 do
			local text = chat1:GetMessageInfo (i)
			if (text) then
				if (text:find ("Hdeath:%d")) then
					local recapID = text:match ("|Hdeath:(%d+)|h")
					if (recapID) then
						recapIDFromChat = tonumber (recapID)
					end
					break
				end
			end
		end
	end
	
	if (recapIDFromChat) then
		Details.OpenDetailsDeathRecap (nil, recapIDFromChat, true)
		return
	end
end

function Details.OpenDetailsDeathRecap (segment, RecapID, fromChat)
    if (not Details.death_recap.enabled) then
        if (Details.DeathRecap and Details.DeathRecap.Lines) then
            for i = 1, 10 do
                Details.DeathRecap.Lines [i]:Hide()
            end
            for i, button in ipairs (Details.DeathRecap.Segments) do
                button:Hide()
            end
        end

        return
    end

    --hide blizzard death recap
    DeathRecapFrame.Recap1:Hide()
    DeathRecapFrame.Recap2:Hide()
    DeathRecapFrame.Recap3:Hide()
    DeathRecapFrame.Recap4:Hide()
    DeathRecapFrame.Recap5:Hide()

    --create details death recap if not existant
    if (not Details.DeathRecap) then
        Details.DeathRecap = CreateFrame ("frame", "DetailsDeathRecap", DeathRecapFrame, "BackdropTemplate")
        Details.DeathRecap:SetAllPoints()
        
        DeathRecapFrame.Title:SetText (DeathRecapFrame.Title:GetText() .. " (by Details!)")
        
        --lines
        Details.DeathRecap.Lines = {}
        for i = 1, 10 do
            Details.DeathRecap.Lines [i] = create_deathrecap_line (Details.DeathRecap, i)
        end
        
        --segments
        Details.DeathRecap.Segments = {}
        for i = 5, 1, -1 do
            local segmentButton = CreateFrame ("button", "DetailsDeathRecapSegmentButton" .. i, Details.DeathRecap, "BackdropTemplate")
            
            segmentButton:SetSize (16, 20)
            segmentButton:SetPoint ("topright", DeathRecapFrame, "topright", (-abs (i-6) * 22) - 10, -5)
            
            local text = segmentButton:CreateFontString (nil, "overlay", "GameFontNormal")
            segmentButton.text = text
            text:SetText ("#" .. i)
            text:SetPoint ("center")
            Details.gump:SetFontColor (text, "silver")
            
            segmentButton:SetScript ("OnClick", function()
                OpenDetailsDeathRecapAtSegment (i)
            end)
            tinsert (Details.DeathRecap.Segments, i, segmentButton)
        end
    end

    for i = 1, 10 do
        Details.DeathRecap.Lines[i]:Hide()
    end

    --segment to use
    local death = Details.tabela_vigente.last_events_tables

    --see if this segment has a death for the player
    local foundPlayer = false
    for index = #death, 1, -1 do
        if (death [index] [3] == Details.playername) then
            foundPlayer = true
            break
        end
    end

    --in case a combat has been created after the player death, the death won't be at the current segment
    if (not foundPlayer) then
        local segmentHistory = Details:GetCombatSegments()
        for i = 1, 2 do
            local segment = segmentHistory [1]
            if (segment and segment ~= Details.tabela_vigente) then
                if (Details.tabela_vigente.start_time - 3 < segment.end_time) then
                    death = segment.last_events_tables
                end
            end
        end
    end

    --segments
    if (Details.death_recap.show_segments) then
        local last_index = 0
        local buttonsInUse = {}
        for i, button in ipairs (Details.DeathRecap.Segments) do
            if (Details.tabela_historico.tabelas [i]) then
                button:Show()
                tinsert (buttonsInUse, button)
                Details.gump:SetFontColor (button.text, "silver")
                last_index = i
            else
                button:Hide()
            end
        end
        
        local buttonsInUse2 = {}
        for i = #buttonsInUse, 1, -1 do
            tinsert (buttonsInUse2, buttonsInUse[i])
        end
        for i = 1, #buttonsInUse2 do
            local button = buttonsInUse2 [i]
            button:ClearAllPoints()
            button:SetPoint ("topright", DeathRecapFrame, "topright", (-i * 22) - 10, -5)
        end
        
        if (not segment) then
            Details.gump:SetFontColor (Details.DeathRecap.Segments [1].text, "orange")
        else
            Details.gump:SetFontColor (Details.DeathRecap.Segments [segment].text, "orange")
            death = Details.tabela_historico.tabelas [segment] and Details.tabela_historico.tabelas [segment].last_events_tables
        end
        
    else
        for i, button in ipairs (Details.DeathRecap.Segments) do
            button:Hide()
        end
    end

    --if couldn't find the requested log from details!, so, import the log from the blizzard death recap
    --or if the player cliced on the chat link for the recap
    local ArtificialDeathLog
    if (not death or RecapID) then
        if (segment) then
            --nop, the player requested a death log from details it self but the log does not exists
            DeathRecapFrame.Unavailable:Show()
            return
        end

        --get the death events from the blizzard's recap
        ArtificialDeathLog = Details.BuildDeathTableFromRecap (RecapID)
    end
    
    DeathRecapFrame.Unavailable:Hide()
    
    --get the relevance config
    local relevanceTime = Details.death_recap.relevance_time

    local t
    if (ArtificialDeathLog) then
        t = ArtificialDeathLog
    else
        for index = #death, 1, -1 do
            if (death [index] [3] == Details.playername) then
                t = death [index]
                break
            end
        end
    end

    if (t) then
        local events = t [1]
        local timeOfDeath = t [2]
        
        local BiggestDamageHits = {}
        for i = #events, 1, -1 do
            tinsert (BiggestDamageHits, events [i])
        end
        table.sort (BiggestDamageHits, function (t1, t2) 
            return t1[3] > t2[3]
        end)
        for i = #BiggestDamageHits, 1, -1 do
            if (BiggestDamageHits [i][4] + relevanceTime < timeOfDeath) then
                tremove (BiggestDamageHits, i)
            end
        end
        
        --check if the event which killed the player is in the list, or addit to BiggestDamageHits
        local hitKill
        for i = #events, 1, -1 do
            local event = events [i]
            local evType = event [1]
            if (type (evType) == "boolean" and evType) then
                hitKill = event
                break
            end
        end
        if (hitKill) then
            local haveHitKill = false
            for index, t in ipairs (BiggestDamageHits) do
                if (t == hitKill) then
                    haveHitKill = true
                    break
                end
            end
            if (not haveHitKill) then
                tinsert (BiggestDamageHits, 1, hitKill)
            end
        end

        --check if there's at least 10 big events, if not fill with smaller events
        if (#BiggestDamageHits < 10) then
            for i = #events, 1, -1 do
                local event = events [i]
                local evType = event [1]
                if (type (evType) == "boolean" and evType) then
                    local alreadyHave = false
                    for index, t in ipairs (BiggestDamageHits) do
                        if (t == event) then
                            alreadyHave = true
                            break
                        end
                    end
                    if (not alreadyHave) then
                        tinsert (BiggestDamageHits, event)
                        if (#BiggestDamageHits == 10) then
                            break
                        end
                    end
                end
            end
        else
            --cut table to show only 10 events
            while (#BiggestDamageHits > 10) do 
                tremove (BiggestDamageHits, 11)
            end
        end

        if (#BiggestDamageHits == 0) then
            if (not fromChat) then
                Details.GetDeathRecapFromChat()
                return
            end
        end	

        table.sort (BiggestDamageHits, function (t1, t2) 
            return t1[4] > t2[4]
        end)

        local events = BiggestDamageHits
        
        local maxHP = t [5]
        local lineIndex = 10
        
        --for i = #events, 1, -1 do
        for i, event in ipairs (events) do 
            local event = events [i]
            
            local evType = event [1]
            local hp = min (floor (event [5] / maxHP * 100), 100)
            local spellName, _, spellIcon = Details.GetSpellInfo (event [2])
            local amount = event [3]
            local eventTime = event [4]
            local source = event [6]
            local overkill = event [10] or 0
            
            local customSpellInfo = event [11]
            
            if (type (evType) == "boolean" and evType) then
                
                local line = Details.DeathRecap.Lines [lineIndex]
                if (line) then
                    line.timeAt:SetText (format ("%.1f", eventTime - timeOfDeath) .. "s")
                    line.spellIcon:SetTexture (spellIcon or customSpellInfo and customSpellInfo [3] or "")
                    line.TopFader:Hide()
                    --line.spellIcon:SetTexCoord (.1, .9, .1, .9)
                    --line.sourceName:SetText ("|cFFC6B0D9" .. source .. "|r")
                    
                    --parse source and cut the length of the string after setting the spellname and source
                    local sourceClass = Details:GetClass (source)
                    local sourceSpec = Details:GetSpec (source)
                    
                    if (not sourceClass) then
                        local combat = Details:GetCurrentCombat()
                        if (combat) then
                            local sourceActor = combat:GetActor (1, source)
                            if (sourceActor) then
                                sourceClass = sourceActor.classe
                            end
                        end
                    end
                    
                    if (not sourceSpec) then
                        local combat = Details:GetCurrentCombat()
                        if (combat) then
                            local sourceActor = combat:GetActor (1, source)
                            if (sourceActor) then
                                sourceSpec = sourceActor.spec
                            end
                        end
                    end
                    
                    --> remove real name or owner name
                    source = Details:GetOnlyName (source)
                    --> remove owner name
                    source = source:gsub ((" <.*"), "")
                    
                    --> if a player?
                    if (Details.player_class [sourceClass]) then
                        source = Details:AddClassOrSpecIcon (source, sourceClass, sourceSpec, 16, true)
                        
                    elseif (sourceClass == "PET") then
                        source = Details:AddClassOrSpecIcon (source, sourceClass)
                    
                    end

                    --> remove the dot signal from the spell name
                    if (not spellName) then
                        spellName = customSpellInfo and customSpellInfo [2] or "*?*"
                        if (spellName:find (STRING_ENVIRONMENTAL_DAMAGE_FALLING)) then
                            if (UnitName ("player") == "Elphaba") then
                                spellName = "Gravity Won!, Elphaba..."
                                source = ""
                            else
                                source = "Gravity"
                            end
                            --/run for a,b in pairs (_G) do if (type (b)=="string" and b:find ("Falling")) then print (a,b) end end
                        end
                    end
                    
                    spellName = spellName:gsub (L["STRING_DOT"], "")
                    spellName = spellName:gsub ("[*] ", "")
                    source = source or ""
                    
                    line.sourceName:SetText (spellName .. " (" .. "|cFFC6B0D9" .. source .. "|r" .. ")")
                    DetailsFramework:TruncateText (line.sourceName, 185)
                    
                    if (amount > 1000) then
                        --line.amount:SetText ("-" .. Details:ToK (amount))
                        line.amount:SetText ("-" .. amount)
                    else
                        line.amount:SetText ("-" .. floor (amount))
                    end
                    
                    line.lifePercent:SetText (hp .. "%")
                    line.lifeStatusBar:SetWidth(line:GetWidth() * (hp/100))

                    line.spellid = event [2]
                    
                    line:Show()
                    
                    if (Details.death_recap.show_life_percent) then
                        line.lifePercent:Show()
                        line.amount:SetPoint ("left", line, "left", 240, 0)
                        line.lifePercent:SetPoint ("left", line, "left", 320, 0)
                    else
                        line.lifePercent:Hide()
                        line.amount:SetPoint ("left", line, "left", 280, 0)
                        --line.lifePercent:SetPoint ("left", line, "left", 320, 0)
                    end
                end
                
                lineIndex = lineIndex - 1
            end
        end
        
        local lastLine = Details.DeathRecap.Lines [lineIndex + 1]
        if (lastLine) then
            lastLine.TopFader:Show()
        end
        
        DeathRecapFrame.Unavailable:Hide()
    else
        if (not fromChat) then
            Details.GetDeathRecapFromChat()
        end
    end
end

hooksecurefunc (_G, "DeathRecap_LoadUI", function()
	hooksecurefunc (_G, "DeathRecapFrame_OpenRecap", function(RecapID)
        local currentCombat = Details:GetCurrentCombat()
        --get the player current death and link the death table with the death recapID
        local playerDeaths = currentCombat:GetPlayerDeaths(UnitName("player"))
        if (playerDeaths) then
            local latestDeath = playerDeaths[#playerDeaths]
            if (latestDeath) then
                latestDeath.RecapID = RecapID

                --synchronize last events from Details! and Blizzard recap
                local events = DeathRecap_GetEvents(recapID)
                --death is event index 1 (the event that killed the player)
                local evtData = events[1]

                if (evtData) then
                    --recap by blizzard
                    local spellName = evtData.spellName
                    local spellId = evtData.spellId
                    local event = evtData.event
                    local environmentalType = evtData.environmentalType
                    local timeStamp = evtData.timestamp
                    local amountDamage = evtData.amount
                    local overkill = evtData.overkill
                    local absorbed = evtData.absorbed
                    local resisted = evtData.resisted
                    local blocked = evtData.blocked
                    local currentHp = evtData.currentHP
                    local hideCaster = evtData.hideCaster
                    local sourceName = evtData.sourceName
                    local casterPrestige = evtData.casterPrestige
                    local spellSchool = evtData.school

                    if (Details.death_recap.enabled) then
                        print("Blizzard DeathRecap: ", spellName, "amount:", amountDamage)
                    end

                    --recap by Details!
                    local deathEventsDetails = latestDeath[1]
                    for evIndex = #deathEventsDetails, 1, -1 do
                        local ev = deathEventsDetails[evIndex]
                        local evType = ev[1]
                        local spellId = ev[2]
                        local amount = ev[3]
                        --is a damage? true boolean
                        if (type(evType) == "boolean" and evType) then
                            local spellName, _, spellIcon = Details.GetSpellInfo(spellId)
                            if (spellName) then
                                --print("Killed by (Details!-Debug): ", spellName, "amount:", amount)
                            else
                                --print("Killed by (Details!-Debug): spell not found")
                            end
                            break
                        end
                    end

                    --Details:Msg("the message above are debugs of an Alpha version of Details!")

                    local whatKilledThePlayer = 0
                end
            end
        end

		Details.OpenDetailsDeathRecap(nil, RecapID)
	end)
end)

--[=[ hooks not loaded at this point
Details:InstallHook(DETAILS_HOOK_DEATH, function(_, _, _, _, _, _, _, targetName)
    if (targetName == UnitName("player")) then
        
    end
end)
--]=]
