-------------------------------------------------------------------------------
-- Module Declaration
--

local plugin = BigWigs:NewPlugin("Pull")
if not plugin then return end

-------------------------------------------------------------------------------
-- Locals
--

local L = BigWigsAPI:GetLocale("BigWigs: Plugins")
local GetInstanceInfo = BigWigsLoader.GetInstanceInfo
local SendAddonMessage = BigWigsLoader.SendAddonMessage
local isLogging = false
local IsEncounterInProgress, PlaySoundFile = IsEncounterInProgress, PlaySoundFile
local media = LibStub("LibSharedMedia-3.0")
local SOUND = media.MediaType and media.MediaType.SOUND or "sound"

-------------------------------------------------------------------------------
-- Options
--

do
	local voiceMap = {
		deDE = "deDE: Default (Female)",
		esES = "esES: Default (Female)",
		esMX = "esMX: Default (Female)",
		frFR = "frFR: Default (Female)",
		itIT = "itIT: Default (Female)",
		koKR = "koKR: Default (Female)",
		ptBR = "ptBR: Default (Female)",
		ruRU = "ruRU: Default (Female)",
		zhCN = "zhCN: Default (Female)",
		zhTW = "zhTW: Default (Female)",
	}
	plugin.defaultDB = {
		countType = "emphasized",
		countBegin = 5,
		combatLog = false,
		engageSound = "None",
		startPullSound = "BigWigs: Long",
		endPullSound = "BigWigs: Alarm",
		voice = voiceMap[GetLocale()] or "English: Amy",
	}
end

do
	local function soundGet(info)
		for i, v in next, media:List(SOUND) do
			if v == plugin.db.profile[info[#info]] then
				return i
			end
		end
	end
	local function soundSet(info, value)
		plugin.db.profile[info[#info]] = media:List(SOUND)[value]
	end

	local function voiceSorting()
		local list = BigWigsAPI:GetCountdownList()
		local sorted = {}
		for k in next, list do
			if k ~= L.none then
				sorted[#sorted + 1] = k
			end
		end
		sort(sorted, function(a, b) return list[a] < list[b] end)
		tinsert(sorted, 1, L.none)
		return sorted
	end

	plugin.pluginOptions = {
		name = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Pull:20|t ".. L.pull,
		type = "group",
		childGroups = "tab",
		get = function(i) return plugin.db.profile[i[#i]] end,
		set = function(i, value) plugin.db.profile[i[#i]] = value end,
		order = 6,
		args = {
			countType = {
				type = "select",
				name = L.countdownType,
				order = 1,
				values = {
					normal = L.normal,
					emphasized = L.emphasized,
				},
			},
			countBegin = {
				name = L.countdownBegins,
				desc = L.countdownBegins_desc,
				type = "range", min = 5, max = 10, step = 1,
				order = 2,
			},
			spacer1 = {
				type = "description",
				name = "\n",
				order = 3,
				width = "full",
			},
			engageSound = {
				type = "select",
				name = L.engageSoundTitle,
				order = 4,
				get = soundGet,
				set = soundSet,
				values = media:List(SOUND),
				width = 2,
				itemControl = "DDI-Sound",
			},
			spacer2 = {
				type = "description",
				name = "\n",
				order = 5,
				width = "full",
			},
			startPullSound = {
				type = "select",
				name = L.pullStartedSoundTitle,
				order = 6,
				get = soundGet,
				set = soundSet,
				values = media:List(SOUND),
				width = 2,
				itemControl = "DDI-Sound",
			},
			endPullSound = {
				type = "select",
				name = L.pullFinishedSoundTitle,
				order = 7,
				get = soundGet,
				set = soundSet,
				values = media:List(SOUND),
				width = 2,
				itemControl = "DDI-Sound",
			},
			voice = {
				name = L.countdownVoice,
				type = "select",
				values = BigWigsAPI.GetCountdownList,
				sorting = voiceSorting,
				order = 8,
				width = 2,
			},
			spacer3 = {
				type = "description",
				name = "\n",
				order = 9,
				width = "full",
			},
			combatLog = {
				type = "toggle",
				name = L.combatLog,
				desc = L.combatLogDesc,
				order = 10,
				width = "full",
			},
		},
	}
end

-------------------------------------------------------------------------------
-- Initialization
--

do
	local function updateProfile()
		local db = plugin.db.profile

		for k, v in next, db do
			local defaultType = type(plugin.defaultDB[k])
			if defaultType == "nil" then
				db[k] = nil
			elseif type(v) ~= defaultType then
				db[k] = plugin.defaultDB[k]
			end
		end

		if db.countType ~= "normal" and db.countType ~= "emphasized" then
			db.countType = plugin.defaultDB.countType
		end
		if db.countBegin < 5 or db.countBegin > 10 then
			db.countBegin = plugin.defaultDB.countBegin
		end
	end

	function plugin:OnPluginEnable()
		self:RegisterMessage("BigWigs_PluginComm")
		self:RegisterMessage("DBM_AddonMessage")

		self:RegisterMessage("BigWigs_OnBossWin")
		self:RegisterMessage("BigWigs_OnBossWipe", "BigWigs_OnBossWin")

		self:RegisterMessage("BigWigs_OnBossEngage")

		self:RegisterMessage("BigWigs_ProfileUpdate", updateProfile)
		updateProfile()
	end
end

function plugin:OnPluginDisable()
	if isLogging then
		isLogging = false
		LoggingCombat(isLogging)
	end
end

-------------------------------------------------------------------------------
-- Event Handlers
--

do
	local timer, timeLeft = nil, 0
	local function printPull(self)
		timeLeft = timeLeft - 1
		if timeLeft == 0 then
			self:CancelTimer(timer)
			timer = nil
			if self.db.profile.countType == "emphasized" then
				self:SendMessage("BigWigs_StopCountdown", self, "pulling time") -- Remove the countdown text
			end
			local soundName = self.db.profile.endPullSound
			if soundName ~= "None" then
				local sound = media:Fetch(SOUND, soundName, true)
				if sound then
					PlaySoundFile(sound, "Master")
				end
			end
		elseif timeLeft > 2 and IsEncounterInProgress() then -- Cancel the pull timer if we ninja pulled
			self:CancelTimer(timer)
			timeLeft = 0
			BigWigs:Print(L.pullStoppedCombat)
			self:SendMessage("BigWigs_StopBar", self, L.pull)
			self:SendMessage("BigWigs_StopPull", self, "COMBAT")
			self:SendMessage("BigWigs_StopCountdown", self, "pulling time")
		elseif timeLeft <= self.db.profile.countBegin and self.db.profile.countType ~= "emphasized" then
			self:SendMessage("BigWigs_Message", self, nil, L.pullIn:format(timeLeft), "yellow")
		end
	end
	function plugin:StartPull(seconds, nick, isDBM)
		if IsEncounterInProgress() then return end -- Doesn't make sense to allow this in combat
		if not IsInGroup() or UnitIsGroupLeader(nick) or UnitIsGroupAssistant(nick) then
			local _, _, _, instanceId = UnitPosition("player")
			local _, _, _, tarInstanceId = UnitPosition(nick)
			if instanceId ~= tarInstanceId then -- Don't fire pull timers from people in different zones
				return
			end

			seconds = tonumber(seconds)
			if not seconds or seconds < 0 or seconds > 60 then return end
			seconds = floor(seconds)
			if timeLeft == seconds then return end -- Throttle
			timeLeft = seconds
			if timer then
				self:CancelTimer(timer)
				if seconds == 0 then
					timeLeft = 0
					BigWigs:Print(L.pullStopped:format(nick))
					self:SendMessage("BigWigs_StopBar", self, L.pull)
					self:SendMessage("BigWigs_StopPull", self, nick, isDBM)
					self:SendMessage("BigWigs_StopCountdown", self, "pulling time")
					return
				end
			end
			FlashClientIcon()
			BigWigs:Print(L.pullStarted:format(isDBM and "DBM" or "BigWigs", nick))
			timer = self:ScheduleRepeatingTimer(printPull, 1, self)

			if self.db.profile.combatLog then
				isLogging = true
				LoggingCombat(isLogging)
			end

			self:SendMessage("BigWigs_StartCountdown", self, nil, "pulling time", timeLeft, self.db.profile.voice, self.db.profile.countBegin, self.db.profile.countType ~= "emphasized")
			self:SendMessage("BigWigs_Message", self, nil, L.pullIn:format(timeLeft), "yellow")
			self:SendMessage("BigWigs_StartBar", self, nil, L.pull, seconds, 132337) -- 132337 = "Interface\\Icons\\ability_warrior_charge"
			self:SendMessage("BigWigs_StartPull", self, seconds, nick, isDBM)
			local soundName = self.db.profile.startPullSound
			if soundName ~= "None" then
				local sound = media:Fetch(SOUND, soundName, true)
				if sound then
					PlaySoundFile(sound, "Master")
				end
			end
		end
	end
end

function plugin:DBM_AddonMessage(_, sender, prefix, seconds)
	if prefix == "PT" then
		self:StartPull(seconds, sender, true)
	end
end

function plugin:BigWigs_PluginComm(_, msg, seconds, sender)
	if msg == "Pull" and seconds then
		self:StartPull(seconds, sender)
	end
end

function plugin:BigWigs_OnBossWin()
	if isLogging then
		isLogging = false
		self:ScheduleTimer(LoggingCombat, 2, isLogging) -- Delay to prevent any death events being cut out the log
	end
end

function plugin:BigWigs_OnBossEngage(_, module)
	if module and module.allowWin then
		local soundName = self.db.profile.engageSound
		if soundName ~= "None" then
			local sound = media:Fetch(SOUND, soundName, true)
			if sound then
				PlaySoundFile(sound, "Master")
			end
		end
	end
end

-------------------------------------------------------------------------------
-- Slash Handler
--

local isBC = BigWigsLoader.isBC
SlashCmdList.BIGWIGSPULL = function(input)
	if IsEncounterInProgress() then BigWigs:Print(L.encounterRestricted) return end -- Doesn't make sense to allow this in combat
	if not IsInGroup() or UnitIsGroupLeader("player") or UnitIsGroupAssistant("player") then -- Solo or leader/assist
		if not plugin:IsEnabled() then BigWigs:Enable() end
		if input == "" then
			input = "10" -- Allow typing /pull to start a 10 second pull timer
		else
			local seconds = tonumber(input)
			if not seconds or seconds < 0 or seconds > 60 then BigWigs:Print(L.wrongPullFormat) return end
			if seconds ~= 0 then
				BigWigs:Print(L.sendPull)
			end
		end

		plugin:Sync("Pull", input)

		if IsInGroup() then
			local _, _, _, _, _, _, _, id = GetInstanceInfo()
			local instanceId = tonumber(id) or 0
			SendAddonMessage(isBC and "D4BC" or "D4C", ("PT\t%s\t%d"):format(input, instanceId), IsInGroup(2) and "INSTANCE_CHAT" or "RAID") -- DBM message
		end
	else
		BigWigs:Print(L.requiresLeadOrAssist)
	end
end
SLASH_BIGWIGSPULL1 = "/pull"
