local addonname, addontbl = ...
local addon = LibStub("AceAddon-3.0"):NewAddon(addonname, "AceEvent-3.0", "AceTimer-3.0")
local L = addontbl.L

function addon:OnInitialize()
end

function addon:OnEnable()
	-- DB
	local defaults = {
		profile = {
			minthreat = 5000,
			dynamic_minthreat = true,
			enabled_in = { dungeon = true, raid = false },
			icon_recycle = true,
			icon_recycle_time = 50
		}
	}
	self.db = LibStub("AceDB-3.0"):New("KungalooshDB", defaults, true)

	-- Work around weird AceDB behaviour..
	if not self.db.profile.raid_icons then
		self.db.profile.raid_icons = { 8, 7, 1, 2 }
	end

	self:CreateConfig()

	self:UnregisterEvent"ADDON_LOADED"
	self:RegisterEvent"PLAYER_ROLES_ASSIGNED"
	self:RegisterEvent"PLAYER_ENTERING_WORLD"

	self:EnableIfTank()
end

function addon:Print(...)
	print("|cFF33FF99Kungaloosh|r "..string.format(...))
end

function addon:PLAYER_ROLES_ASSIGNED()
	self:EnableIfTank()
end

function addon:PLAYER_ENTERING_WORLD()
	self:EnableIfTank()
end

function addon:PLAYER_REGEN_ENABLED()
	self:ResetState()
end

function addon:UNIT_THREAT_LIST_UPDATE(event, unit)
	if not unit then return end

	local guid = UnitGUID(unit)
	local icon = self:GetRaidIconByGUID(guid) or self:GetNextIcon()

	if icon and GetRaidTargetIndex(unit) == nil then
		local istanking, status, threatpct, rawthreatpct, threat = UnitDetailedThreatSituation("player", unit)

		if threat and threat > (self:GetMinThreat() * 100) then
			SetRaidTarget(unit, icon)
		end
	end
end

function addon:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, cevent, hidecaster,
                                           sguid, sname, sflags, sflags2,
                                           dguid, dname, dflags, dflags2)
	if cevent == "UNIT_DIED" then
		local icon = self:GetRaidIconByGUID(dguid)
		if icon and self.db.profile.icon_recycle then
			self:ScheduleTimer("ResetIcon", self.db.profile.icon_recycle_time, icon)
		end
	end
end

function addon:CheckUnit(unit)
	if UnitExists(unit) then
		local icon = GetRaidTargetIndex(unit)
		local guid = UnitGUID(unit)

		if icon then
			local oldguid = self:GetGUIDByRaidIcon(icon)
			local oldicon = self:GetRaidIconByGUID(guid)

			if guid ~= oldguid then
				if oldicon then
					self:ResetIcon(oldicon)
				end

				self:SetIconGUID(icon, guid)
			end
		else
			local oldicon = addon:GetRaidIconByGUID(guid)

			if oldicon then
				self:ResetIcon(oldicon)
			end
		end
	end
end

function addon:RAID_TARGET_UPDATE()
	self:CheckUnit"player"
	self:CheckUnit"focus"
	self:CheckUnit"target"
	self:CheckUnit"targettarget"
	self:CheckUnit"pet"
	self:CheckUnit"pettarget"

	for i = 1,40 do
		if i <= 5 then
			self:CheckUnit("party"..i)
			self:CheckUnit("party"..i.."target")
		end

		self:CheckUnit("raid"..i)
		self:CheckUnit("raid"..i.."target")
	end
end

function addon:ResetState()
	self:CancelAllTimers()

	self.iconguids = self.iconguids or {}
	table.wipe(self.iconguids)
end

function addon:ResetIcon(icon)
	self.iconguids[icon] = nil
end

function addon:SetIconGUID(icon, guid)
	self.iconguids[icon] = guid
end

function addon:GetRaidIconByGUID(guid)
	for icon, iguid in pairs(self.iconguids) do
		if guid == iguid then
			return icon
		end
	end
end

function addon:GetGUIDByRaidIcon(icon)
	return self.iconguids[icon]
end

function addon:GetNextIcon()
	for i, icon in ipairs(self.db.profile.raid_icons) do
		if not addon:GetGUIDByRaidIcon(icon) then
			return icon
		end
	end
end

function addon:GetMinThreat()
	if self.db.profile.dynamic_minthreat then
		local level = UnitLevel"player"
		local multiplier = (level > 80 and 3.0) or 1.2

		return (level * level) * multiplier
	else
		return self.db.profile.minthreat
	end
end

function addon:EnableIfTank()
	if self.force_enabled then return end

	local istank = (UnitGroupRolesAssigned("player") == "TANK") or (GetPartyAssignment("MAINTANK", "player") == 1)

	if istank then
		local enable = false

		if self.db.profile.enabled_in.dungeon and not UnitInRaid"player" then
			enable = true
		end

		if self.db.profile.enabled_in.raid and UnitInRaid"player" then
			enable = true
		end

		if enable then
			return self:Enable(L["is now enabled since you are assigned as a tank"])
		end
	end

	return self:Disable()
end

function addon:Enable(msg)
	if self.enabled then return end

	self:RegisterEvent"PLAYER_REGEN_ENABLED"
	self:RegisterEvent"UNIT_THREAT_LIST_UPDATE"
	self:RegisterEvent"RAID_TARGET_UPDATE"
	self:RegisterEvent"COMBAT_LOG_EVENT_UNFILTERED"
	self.enabled = true

	self:ResetState()

	if msg then self:Print(msg) end
end

function addon:Disable(msg)
	if not self.enabled then return end

	self:UnregisterEvent"PLAYER_REGEN_ENABLED"
	self:UnregisterEvent"UNIT_THREAT_LIST_UPDATE"
	self:UnregisterEvent"RAID_TARGET_UPDATE"
	self:UnregisterEvent"COMBAT_LOG_EVENT_UNFILTERED"
	self.enabled = false

	if msg then self:Print(msg) end
end

function addon:Toggle()
	if not self.enabled then
		self:Enable(L["is now enabled"])
		self.force_enabled = true
	else
		self:Disable(L["is now disabled"])
		self.force_enabled = false
	end
end

function SlashCmdList.KUNGALOOSH()
	addon:Toggle()
end

_G["SLASH_KUNGALOOSH1"] = "/kungaloosh"
_G["SLASH_KUNGALOOSH2"] = "/kl"
_G["Kungaloosh"] = addon
