-- 부활 시전바 모듈
local RaidComm = LibStub("LibRaidComm-1.0", true)
if not RaidComm then return end

local IRF2 = InvenRaidFrames2

local _G = _G
local unpack = _G.unpack
local pairs = _G.pairs
local GetTime = _G.GetTime
local GetRealmName = _G.GetRealmName
local UnitName = _G.UnitName
local GetUnitName = _G.GetUnitName
local UnitCastingInfo = _G.UnitCastingInfo
local UnitIsDeadOrGhost = _G.UnitIsDeadOrGhost

local resInfoCaster, resInfoTarget, resInfoStartTime, resInfoEndTime = {}, {}, {}, {}
local targetSaver, target, targetName, fullName = {}
local spell, startTime, endTime, setCaster, endTimer, unitfName
local resurrectionSpell = { [GetSpellInfo(20777)] = true, [GetSpellInfo(25435)] = true, [GetSpellInfo(20773)] = true, [GetSpellInfo(50764)] = true, [GetSpellInfo(20484)] = true }
local firstRun = true
local eventHandler = CreateFrame("Frame")
eventHandler:SetScript("OnEvent", function(self, event, ...) self[event](self, ...) end)

local function GetRealName(name)
	if name then
		return name:gsub("-"..GetRealmName(), "")
	end
	return name
end

local function rcGetCastingTarget(name)
	if RaidComm:GetCastingTarget(name) == "무엇인가" then
		return nil
	else
		return GetRealName(RaidComm:GetCastingTarget(name))
	end
end

local function GetTarget(unit)
	unitfName = IRF2:GetUnitName(unit)
	return GetRealName(rcGetCastingTarget(unitfName) or targetSaver[unitfName] or targetSaver[unitfName])
end

function eventHandler:CHAT_MSG_ADDON(prefix, msg, distribution, sender)
	-- CTRA, oRA, oRA2 등의 애드온 부활 메시지 후킹
	if prefix == "CTRA" and sender ~= UnitName("player") then
		targetName = msg:match("^RES (.+)$")
		if targetName and targetName ~= "무엇인가" then
			targetSaver[sender] = GetRealName(targetName)
		end
	end
end

local function resBarOnUpdate(self)
	if self:GetParent().unit then
		if UnitIsDeadOrGhost(self:GetParent().unit) then
			-- 부활 캐스팅 바 업데이트
			self:SetValue(GetTime())
		else
			-- 부활 캐스팅 중 캐릭터가 부활되면 캐스팅바 숨김
			self:Hide()
		end
	end
end

local function createResBar(object)
	if not object.resCastingBar then
		object.resCastingBar = CreateFrame("StatusBar", nil, object)
		object.resCastingBar:SetAllPoints(object)
		object.resCastingBar:SetFrameLevel(IRF2.db.frameLevel.resCastingBar)
		object.resCastingBar:SetStatusBarTexture(object.health:GetStatusBarTexture():GetTexture())
		object.resCastingBar:SetStatusBarColor(unpack(IRF2.db.resurrection.color))
		object.resCastingBar:Hide()
		object.resCastingBar:SetScript("OnUpdate", resBarOnUpdate)
		object.resCastingBar:SetAlpha(IRF2.db.resurrection.use and 1 or 0)
	end
end

local function resBarUpdate(name)
	-- 부활 받는 대상자의 부활 시전바 업데이트
	if resInfoCaster[name] and IRF2.names[name] then
		endTimer, setCaster = 0, nil
		for caster in pairs(resInfoCaster[name]) do
			if resInfoEndTime[caster] then
				if endTimer == 0 then
					endTimer = resInfoEndTime[caster]
					setCaster = caster
				elseif endTimer > resInfoEndTime[caster] then
					endTimer = resInfoEndTime[caster]
					setCaster = caster
				end
			end
		end
		if setCaster and resInfoStartTime[setCaster] and resInfoEndTime[setCaster] then
			for i = 1, #IRF2.names[name] do
				createResBar(IRF2.names[name][i])
				if IRF2.names[name][i].resCastingBar then
					IRF2.names[name][i].resCastingBar:SetMinMaxValues(resInfoStartTime[setCaster], resInfoEndTime[setCaster])
					IRF2.names[name][i].resCastingBar:Show()
				end
			end
		end
	end
end

local function resBarClear(name)
	-- 부활 받는 대상자의 부활 시전바 초기화
	if resInfoCaster[name] and IRF2.names[name] then
		-- 부활 대상자에게 부활을 시전하는 다른 이가 있는 경우 다시 시전바 업데이트
		for caster in pairs(resInfoCaster[name]) do
			resBarUpdate(name)
			return
		end
		-- 부활 대상자에게 아무도 부활을 하지 않는 경우 시전바를 숨김
		for i = 1, #IRF2.names[name] do
			if IRF2.names[name][i].resCastingBar then
				IRF2.names[name][i].resCastingBar:Hide()
			end
		end
	end
end

function eventHandler:UNIT_SPELLCAST_START(unit)
	fullName = IRF2:GetUnitName(unit)
	if IRF2.units[unit] and IRF2.units[unit]:IsShown() then
		spell, _, _, _, startTime, endTime = UnitCastingInfo(unit)
		if spell and resurrectionSpell[spell] then
			target = GetTarget(unit)
			if target and IRF2.names[target] then
				if resInfoEndTime[fullName] ~= (endTime / 1000) then
					-- 부활 캐스팅 정보 저장
					resInfoCaster[target] = resInfoCaster[target] or {}
					resInfoCaster[target][fullName] = true
					resInfoTarget[fullName] = target
					resInfoStartTime[fullName] = startTime / 1000
					resInfoEndTime[fullName] = endTime / 1000
					resBarUpdate(target)
				end
				return
			end
		end
	end
	if resInfoTarget[fullName] then
		-- 부활 캐스팅이 아닐때 기존 정보 초기화
		if resInfoCaster[resInfoTarget[fullName]] and resInfoCaster[resInfoTarget[fullName]][fullName] then
			resInfoCaster[resInfoTarget[fullName]][fullName] = nil
		end
		resBarClear(resInfoTarget[fullName])
		resInfoTarget[fullName] = nil
		resInfoStartTime[fullName] = nil
		resInfoEndTime[fullName] = nil
	end
end

local function objectResBarUpdate(object)
	if resInfoCaster[object.fullName] then
		for caster in pairs(resInfoCaster[object.fullName]) do
			resBarUpdate(object.fullName)
			return
		end
	end
	if object.resCastingBar then
		object.resCastingBar:Hide()
	end
end

local function resurrection(object)
	if firstRun then
		firstRun = nil
		eventHandler.UNIT_SPELLCAST_STOP = eventHandler.UNIT_SPELLCAST_START
		eventHandler.UNIT_SPELLCAST_DELAYED = eventHandler.UNIT_SPELLCAST_START
		eventHandler:RegisterEvent("CHAT_MSG_ADDON")
		eventHandler:RegisterEvent("UNIT_SPELLCAST_START")
		eventHandler:RegisterEvent("UNIT_SPELLCAST_STOP")
		eventHandler:RegisterEvent("UNIT_SPELLCAST_DELAYED")
	end
	object.UpdateResBar = objectResBarUpdate
end

IRF2:RegisterObjectModule("Resurrection", resurrection)