local DGV = DugisGuideViewer
if not DGV then return end

local DebugPrint = DGV.DebugPrint
local Target, MV = DGV:RegisterModule("Target", "ModelViewer")
--DGV.Target = Target

function Target:ShouldLoad()
	return DGV:UserSetting(DGV_TARGETBUTTON) and DugisGuideViewer.GuideOn()
end

local currentMode = nil
function Target:UpdateMode()
  DGV.DoOutOfCombat(function()

	if currentMode == DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) 
	and not DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then
		return
	end
	
	currentMode = DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE)

	Target.Frame:ClearAllPoints()
	
	if DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then
		if MV and MV.loaded and MV.Frame and MV.Frame.model then
			Target.Frame:SetParent(MV.Frame.model)
			
			local scale = DGV:GetDB(DGV_TARGETBUTTONSCALE)
			
			local top = -12
			local left =  -22 - 2.4 * scale
			
			local targetDeltaY = scale * 0.65 
			local targetYCorrection = -(((scale - 5.5) * (scale - 5.5)) * 0.0495 - 1)
			
			Target.Frame:SetPoint("TOPRIGHT", MV.Frame.model, "BOTTOMRIGHT", 6 - scale * 0.2, top + targetDeltaY + targetYCorrection)
			
			DugisItemButton:ClearAllPoints()
			DugisItemButton:SetPoint("TOPRIGHT", MV.Frame.model, "BOTTOMRIGHT", left, top)
		end
	else
		local left = DugisItemButton:GetLeft()
        local top = -(GetScreenHeight() - (DugisItemButton:GetTop() or 0))

        if not left then
            left = Target.lastLeft or (GetScreenWidth() * 0.5)
            top =  -(GetScreenHeight() -(Target.lastTop or GetScreenHeight()*0.5))
        end

		DugisItemButton:SetParent(UIParent)
		DugisItemButton:ClearAllPoints()
		DugisItemButton:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left, top)
		
		Target.Frame:SetParent(UIParent)
	end
	
	if Target.animation then
		Target.animation:ClearAllPoints();
		Target.animation:SetParent(Target.Frame)
		Target.animation:SetPoint("TOPLEFT", Target.Frame, "TOPLEFT", -2, 2);
		Target.animation:SetPoint("BOTTOMRIGHT", Target.Frame, "BOTTOMRIGHT", 2, -2);	
		
		Target.animation:SetWidth(30)
		Target.animation:SetHeight(30)
	end
  end)
end

function Target:Initialize()

	--Updates target button's size
	local function UpdateTargetButtonSize()
		local DGV_TargetButtonSize = 23 + (DGV:GetDB(DGV_TARGETBUTTONSCALE) * 3);
		Target.Frame:SetSize(25, 25)
        
        local scale = (DugisGuideViewer:UserSetting(DGV_TARGETBUTTONSCALE)-1)/10 + 1
        Target.Frame:SetScale(scale)
		
		if DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then
			Target:UpdateMode()
		end
	end
    
    local function UpdateHotKey()
        local key = GetBindingKey("CLICK DugisGuideViewer_TargetFrame:RightButton")
        if key then 
            Target.Frame.HotKey:SetText(key:sub(1,1))
        else
            Target.Frame.HotKey:SetText("")
        end
    end

	--Make target macro
	local function OnEvent(self, event)
		if event=="PLAYER_REGEN_ENABLED" then
			if DGV:UserSetting(DGV_TARGETBUTTON) and #Target.npcIds>0 then

				Target.numNPCs = #Target.npcIds
				
				if DGV:IsModelDataOn() then 
					Target.npcIndex = MV.data.modelPage 
				else 
					if not Target.npcIndex or Target.npcIndex >= Target.numNPCs then Target.npcIndex = 0 end Target.npcIndex = Target.npcIndex + 1
				end

				Target.macroName = "DugisMacro"
				Target.macroIcon = 203
				Target.npc = DGV:GetLocalizedNPC(Target.npcIds[Target.npcIndex])
				Target.macroBody = "/cleartarget\n/tar "..(Target.npc or "").."\n/run DugisGuideViewer:FinalizeTarget()\n"
				--DebugPrint("macroTarget= "..Target.macroBody)
				if DGV:UserSetting(DGV_TARGETBUTTONCUSTOM) then
					Target.macroBody = Target.macroBody..(Target.customMacro or "")
				else
					--Target.macroBody = Target.macroBody.."\n/script local icon; if UnitIsFriend(\"player\", \"target\") then icon = \"1\" else icon = \"8\" end;"
					--Target.macroBody = Target.macroBody.."if not GetRaidTargetIndex(\"target\") then SetRaidTarget(\"target\", icon) end "
                    
                    local extraOperations = ""
                    
                    if Target.questRelatedScript then
                        extraOperations = "\n/run " .. Target.questRelatedScript 
                    end
                    
					Target.macroBody = Target.macroBody..Target.DefaultMacro..extraOperations
				end

				--local macroIndex = Target:CreateMacro( )
				--if macroIndex then
					Target.Frame:SetAttribute("type", "macro")
					Target.Frame:SetAttribute("macrotext", Target.macroBody)
					if DGV:UserSetting(DGV_TARGETBUTTONSHOW) then Target.Frame:Show() end
				--end
				
				UpdateTargetButtonSize()
				
			else
				Target.Frame:SetAttribute("macro", nil)
				Target.Frame:Hide()
			end

			self:UnregisterEvent("PLAYER_REGEN_ENABLED")
		elseif event == "PLAYER_REGEN_DISABLED" then
			Target.Frame:StopMovingOrSizing()
			Target.Frame.IsMoving = false
		elseif event == "UPDATE_BINDINGS" then
            UpdateHotKey()
		end
	end
    
    local modelFrame = DGV.GUIUtils:CreateModelFrame(GameTooltip, 30)
    modelFrame:SetSize(140, 180)
    modelFrame:SetPoint("TOPLEFT", GameTooltip, "TOPLEFT", 10, -20) 
    modelFrame:Hide()
    
	function InitModelPos(npcId)
		modelFrame.posX = 0
		modelFrame.posY = 0
		modelFrame:SetPosition(0, 0, 0)
        local progdir = 0
        local prog = 0
        
        local modelId = tonumber(npcId)

        local transformation1 = DGV.ObjectModelsExtra[modelId]
        local transformation2  = DGV.DisplayModelsExtra[modelId]
        local transformation3  = DGV.NPCModelsExtra[modelId]
        
        local transformation = transformation1 or transformation2 or transformation3 or {}
        local viewer = modelFrame
        
        viewer:SetCamDistanceScale(1)
        viewer:SetPortraitZoom(0)
        local curfacing = 0
     
        if transformation then
            local modelScale = transformation.scale and max(transformation.scale,0.01) or 1.01
            viewer:SetModelScale(modelScale)
            viewer:SetPosition(transformation.cx or 0,transformation.cy or 0,(transformation.cz or 0))

            if transformation.cam then viewer:SetCamera(transformation.cam) else viewer:RefreshCamera() end
            viewer:SetCamDistanceScale(transformation.camscale and max(transformation.camscale,0.01) or 1.01)
            if transformation.portrait and transformation.portrait>0 then viewer:SetPortraitZoom(transformation.portrait) end
            curfacing = (transformation.facing or 0) / 57.30       
        end
        
        if transformation and transformation.facing then
            viewer:SetFacing(curfacing)   
        end     
            
	end    
    
    function SetModel(npcId)
        modelFrame:Show()
        GameTooltip:SetMinimumWidth(140)
        modelFrame.title:Hide()
		local mv = DGV.Modules.ModelViewer
		modelFrame:Show()
		modelFrame:ClearModel()
		if mv and mv.npcDB and mv.npcDB[npcId] then
			modelFrame:SetDisplayInfo(mv.npcDB[npcId])
		elseif npcId then
			modelFrame:SetCreature(npcId)
		end
        
        InitModelPos(npcId)
    end

	local oldFontName, oldFontSize 
	function Target:ShowTooltip( )
        GameTooltip:SetOwner(Target.Frame, "ANCHOR_RIGHT", 0, 0)            
        GameTooltip:ClearLines() 
        local npcName = DGV:GetLocalizedNPC(Target.npcIds[Target.npcIndex])

        if npcName == nil then
            npcName = ""
        end
		
		oldFontName, oldFontSize = GameTooltipTextLeft1:GetFont()
		GameTooltipTextLeft1:SetFont(oldFontName, 12)

        GameTooltip:AddLine("|cffffffff/target|r " .. npcName, nil, nil, nil, true)
        LuaUtils:loop(12, function(i)
            GameTooltip:AddLine(" ")
        end)
        SetModel(Target.npcIds[1])
        GameTooltip:Show()     
        GameTooltip:SetWidth(180)  
        GameTooltipTextLeft1:SetWidth(160)
    end
    
	function Target:HideTooltip( )
		if oldFontName and oldFontSize then
			GameTooltipTextLeft1:SetFont(oldFontName, oldFontSize)
		end
        GameTooltip:ClearLines() 
        GameTooltip:Hide()  
        modelFrame:Hide()
    end
    
	function Target:CreateFrame( )
		if Target.Frame then return end
		Target.Frame = CreateFrame("Button", "DugisGuideViewer_TargetFrame", UIParent, "DugisTargetButtonTemplate")
        Target.Frame:RegisterEvent("UPDATE_BINDINGS")
        
		Target.Frame:SetClampedToScreen(true);
		--Target.Frame:SetFrameStrata("LOW");
		UpdateTargetButtonSize()
		--Target.Frame:SetPoint("LEFT", "DugisSecureQuestButton", "RIGHT", "5", "0")
		Target.Frame:SetPoint("LEFT", "DugisItemButton", "RIGHT", "5", "0")
		Target.Frame:SetScript("OnUpdate", function(self, elapsed) Target:OnUpdate(self, elapsed) end)
		Target.Frame:SetScript("OnEvent", OnEvent)
		Target.Frame:HookScript("OnClick", DGV.FinalizeTarget)

		Target.Frame:SetNormalTexture("Interface\\AddOns\\DugisGuideViewerZ\\Artwork\\IconBorder")
		Target.Frame:SetPushedTexture("Interface\\Buttons\\UI-Quickslot-Depress")
		Target.Frame:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
		Target.Frame:RegisterForClicks("AnyUp", "AnyDown") --https://github.com/Stanzilla/WoWUIBugs/issues/268
		Target.Frame:RegisterForDrag("LeftButton")
		Target.Frame:SetMovable(true)
		Target.Frame:SetUserPlaced(true)
        
        UpdateHotKey()
        
        Target.Frame:SetScript("OnEnter", function()    
			if DGV:UserSetting(DGV_TARGETTOOLTIP) 
			and not DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then 
          	  Target:ShowTooltip( )    
			end
        end)     

        Target.Frame:HookScript("OnShow", function()    
			Target:UpdateMode()
        end)
        
        Target.Frame:SetScript("OnLeave", function()
            if DGV:UserSetting(DGV_TARGETTOOLTIP) then 
				Target:HideTooltip( )     
			end
        end)
        
		Target.Frame:SetScript("OnDragStart", function(frame)
			if DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then
				return
			end
		
			if not InCombatLockdown() then
				frame:StartMoving();
				frame.IsMoving = true
			end
		end)
		Target.Frame:SetScript("OnDragStop", function(frame)
            Target.lastLeft = Target.Frame:GetLeft()
            Target.lastTop = Target.Frame:GetTop()			
			frame:StopMovingOrSizing()
			frame.IsMoving = false
		end)

		Target.Frame.icon = Target.Frame:CreateTexture(nil, "BORDER")
		Target.Frame.icon:SetTexture("Interface\\Icons\\Ability_Hunter_SniperShot")
		Target.Frame.icon:SetSize("28", "28")
		Target.Frame.icon:SetAllPoints(Target.Frame)
		
		Target:UpdateMode()
	end
   
    -- duration (duration factor):  1 - standard duration , 2 - 2 x longer, 0.5 - 2 x slower
    function Target:PlayAnimation(alpha, duration, loopAnimationDurationSec) --/script DugisGuideViewer.Modules.--Target:PlayAnimation(1, 0.5)
        if duration == nil then
            duration = 1
        end
    
        if alpha == nil then
            alpha = 1
        end
        
        if loopAnimationDurationSec == nil then
            loopAnimationDurationSec = 4
        end
        
        if Target.animation == nil then
            Target.animation = CreateFrame("Frame", "TMW_ActionButtonOverlay" .. 1, Target.Frame, "TargetButtonAnimation")
        end
        
		local animations = {DugisGuideViewer.Modules.Target.animation.ProcStartAnim:GetAnimations()}
		for i=1, #animations do
			if animations[i].origDuration == nil then
				animations[i].origDuration = animations[i]:GetDuration()
			end
			animations[i]:SetDuration(duration * animations[i].origDuration)
		end
        
        Target.animation:SetAlpha(alpha)
		Target.animation:ClearAllPoints();
		Target.animation:SetPoint("TOPLEFT", Target.Frame, "TOPLEFT", -5, 5);
		Target.animation:SetPoint("BOTTOMRIGHT", Target.Frame, "BOTTOMRIGHT", 5, -5);
		
		Target:UpdateMode()
		
        Target.animation:Show()
        Target.animation.ProcStartAnim:Play();
        Target.animation.startTime = GetTime()
        Target.animation.duration = loopAnimationDurationSec
        Target.animation:HookScript("OnUpdate", function(self, elapsed)
            if (GetTime() - Target.animation.startTime) >= Target.animation.duration then
                Target.animation.ProcStartAnim:Stop()
                Target.animation:Hide()
            end
        end)
    end
    
	local function AddNPCs(...)
		for i=1, select("#", ...) do
			local singleVal = select(i, ...)
			table.insert(Target.npcIds, singleVal)
		end
	end

	function Target:AddIndexNPCs(questIndex)
		AddNPCs(DGV:ReturnTag("NPC", questIndex))
	end
    
    function Target:SetIndexNPCs(npcId)
		AddNPCs(npcId)
	end

	function Target:CreateMacro( )

		if InCombatLockdown() then return end

		local index = GetMacroIndexByName(Target.macroName)
		--Macro does not exist, create it
		if index == 0 then
			index = nil
			local numAcctMacros, numCharMacros = GetNumMacros()

			--Character Macro
			if numCharMacros < (MAX_CHARACTER_MACROS or 18) then
				index = CreateMacro(Target.macroName, Target.macroIcon, Target.macroBody, 1)
			end

			--General Macro
			if not index and numAcctMacros < (MAX_ACCOUNT_MACROS or 36) then
				DebugPrint("Character Macros full, trying general area")
				index = CreateMacro(Target.macroName, Target.macroIcon, Target.macroBody)
			end
		else
			EditMacro(index, Target.macroName, Target.macroIcon, Target.macroBody)
		end

		if not index then
			DebugPrint("Create Macro Failed")
		end
		return index
	end


	function Target:CustomizeMacro()
		local inputBox = _G["DGV.InputBox"..DGV_TARGETBUTTONCUSTOM]

		Target.customMacro = inputBox:GetText()
		DGV.chardb[DGV_TARGETBUTTONCUSTOM].editBox = inputBox:GetText()
		DGV:SetTarget(DugisGuideUser.CurrentQuestIndex)
	end

	function Target:ResetMacro( )
		Target.customMacro = Target.DefaultMacro
		DGV.chardb[DGV_TARGETBUTTONCUSTOM].editBox = Target.DefaultMacro
		_G["DGV.InputBox"..DGV_TARGETBUTTONCUSTOM]:SetText(Target.DefaultMacro)
		_G["DGV.InputBox"..DGV_TARGETBUTTONCUSTOM]:SetCursorPosition(0)
		DGV:SetTarget(DugisGuideUser.CurrentQuestIndex)
	end

	function Target:ClearMacro( )
		DGV.chardb[DGV_TARGETBUTTONCUSTOM].editBox = ""
		_G["DGV.InputBox"..DGV_TARGETBUTTONCUSTOM]:SetText("")
		_G["DGV.InputBox"..DGV_TARGETBUTTONCUSTOM]:SetCursorPosition(0)
	end

	--Sticky frames target and item button
	function Target:OnUpdate(self, elapsed)
		if not InCombatLockdown() and self.IsMoving and not DugisGuideViewer:UserSetting(DGV_TRGET_BUTTON_FIXED_MODE) then
			LuaUtils.ClearAndSetPoint(DugisItemButton, "RIGHT", self, "LEFT", "-5", "0")
		end

        if DGV.restoredFramePositions and not Target.lastLeft then
            Target.lastLeft = Target.Frame:GetLeft()
            Target.lastTop = Target.Frame:GetTop()
        end
	end

	Target.npcIds = {}
	Target:CreateFrame( )
	Target.customMacro = DGV.chardb[DGV_TARGETBUTTONCUSTOM].editBox
	
	Target.DefaultMacro = "/run DugisGuideViewer:MarkTarget()"

	function Target:Load()
		--Target.Frame:Show( )

		Target.Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
		function DGV:FinalizeTarget()
			if InCombatLockdown() then
				Target.Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
			else
				OnEvent(Target.Frame, "PLAYER_REGEN_ENABLED")
			end
		end
		DGV:FinalizeTarget()

		function DGV:SetTarget(questIndex)
			local sameNpc = nil
			if Target.npcIds[1] == select(1, DGV:ReturnTag("NPC", questIndex)) then sameNpc = true end
            
            Target.questRelatedScript = DGV:ReturnTag("SCRIPT", questIndex)
			
			DGV:WipeTargetNPCs()
			Target:AddIndexNPCs(questIndex)
			DGV:FinalizeTarget()
    
            if Target.lastSetQuestIndex ~= questIndex and not sameNpc then
                if Target.Frame:IsShown() then
                    Target:PlayAnimation(0.3, 1, 2)
                else
                    Target:PlayAnimation(1, 1, 5)
                end
            end
            Target.lastSetQuestIndex = questIndex
		end
        
        function DGV:SetNPCTarget(npcId)
			local sameNpc = nil
			if Target.npcIds[1] == npcId then sameNpc = true end		
		
			DGV:WipeTargetNPCs()
			Target:SetIndexNPCs(npcId)
			DGV:FinalizeTarget()
			
            if not sameNpc then
                if Target.Frame:IsShown() then
                    Target:PlayAnimation(0.3, 1, 2)
                else
                    Target:PlayAnimation(1, 1, 5)
                end
            end			
		end

		function DGV:WipeTargetNPCs()
			wipe(Target.npcIds)
		end
		
		function DGV:MarkTarget()
			if not GetRaidTargetIndex("target") then 
				if UnitIsFriend("player", "target") then 
					SetRaidTarget("target", "1") 
				else 
					SetRaidTarget("target", "8") 
				end 
			end
		end 
	end

	function Target:Unload()
		DGV:FinalizeTarget()
		Target.Frame:UnregisterEvent("PLAYER_REGEN_DISABLED")
		Target.Frame:Hide( )
	end
end

TargetButtonAnimationMixin = {};
function TargetButtonAnimationMixin:OnUpdate(elapsed)
	AnimateTexCoords(self.ants, 256, 256, 48, 48, 22, elapsed, 0.01);
	local cooldown = self:GetParent().cooldown;
	if(cooldown and cooldown:IsShown() and cooldown:GetCooldownDuration() > 3000) then
		self:SetAlpha(0.5);
	else
		self:SetAlpha(1.0);
	end
end

function TargetButtonAnimationMixin:OnHide()
	if ( self.animOut:IsPlaying() ) then
		self.animOut:Stop();
		self.animOut:OnFinished();
	end
end
