local DGV = DugisGuideViewer
if not DGV then return end

local WF = DGV:RegisterModule("DugisWatchFrame")
WF.essential = true

local function IncompatibleAddonLoaded()
	return (DGV.carboniteloaded and Nx.Quest) or DGV.sexymaploaded or DGV.nuiloaded or DGV.elvuiloaded or DGV.tukuiloaded or DGV.shestakuiloaded or DugisGuideUser.PetBattleOn
end

local smallAndObjectiveFrameOneBkg = true

ObjectiveFrameDugiBkg = CreateFrame("Frame", "ObjectiveFrameDugiBkg", UIParent)
ObjectiveFrameDugiBkg:SetFrameStrata("BACKGROUND")
ObjectiveFrameDugiBkg:SetFrameLevel(8)
ObjectiveFrameDugiBkg:SetWidth(52)
ObjectiveFrameDugiBkg:SetHeight(52)
ObjectiveFrameDugiBkg:SetPoint("CENTER", 0, 220)
ObjectiveFrameDugiBkg:Hide()

ObjectiveFrameDugiBkg:EnableMouse(true)

local lastTrackerX, lastTrackerY

local function GetSmallFrame()
	if DugisGuideViewer.Modules.SmallFrame and DugisGuideViewer.Modules.SmallFrame.Frame then
		return DugisGuideViewer.Modules.SmallFrame
	end
end

function IsSmallFrameCollapsed()
	local SmallFrame = GetSmallFrame()
	return SmallFrame.collapseHeader:IsShown() and SmallFrame.collapsed
end

local function IsObjectiveTrackerVisible()
	return ObjectiveTrackerFrame.HeaderMenu:IsVisible()  and not  ObjectiveTrackerFrame.collapsed  and ObjectiveFrameDugiBkg.initialized
end

ObjectiveFrameDugiBkg:HookScript("OnMouseDown", function()
	--Todo: check if mouse is in ObjectiveTrackerFrame indeed and if ObjectiveTrackerFrame is shown
	
	local SmallFrame = GetSmallFrame()
	
	if DugisGuideViewer:UserSetting(DGV_MOVEWATCHFRAME) and not DugisGuideViewer:UserSetting(DGV_DISABLEWATCHFRAMEMOD) then
		if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
			local frame = ObjectiveTrackerFrame
			frame.startMouseX, frame.startMouseY = GetCursorPosition()
			frame.startFrameX, frame.startFrameY = GUIUtils:GetRealFeamePos(frame)
			frame.startHeaderFrameX, frame.startHeaderFrameY = GUIUtils:GetRealFeamePos(ObjectiveTrackerFrame.HeaderMenu)
			frame.isDragging = true
		else
			SmallFrame.OnDragStart()
		end
	end
end)

ObjectiveFrameDugiBkg:HookScript("OnMouseUp", function()
	local SmallFrame = GetSmallFrame()
	
	if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
		local frame = ObjectiveTrackerFrame
		frame.isDragging = false
	else
		local SmallFrame = GetSmallFrame()
		SmallFrame.OnDragStop()
	end
end)

function ObjectiveFrameDugiBkgDrag()
	if DugisGuideViewer:UserSetting(DGV_DISABLEWATCHFRAMEMOD) then return end

	local frame = ObjectiveTrackerFrame
	
	if frame.isDragging then
		if not IsMouseButtonDown("LeftButton") then
			frame.isDragging = false
		end
	end
	
	if frame.isDragging then
		local SmallFrame = GetSmallFrame()
		if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
			local currentMouseX, currentMouseY = GetCursorPosition()
			local deltaMouseX, deltaMouseY = currentMouseX - frame.startMouseX, currentMouseY - frame.startMouseY
			local newBkgFrameX, newBkgFrameY = frame.startFrameX + deltaMouseX, frame.startFrameY + deltaMouseY
			local newHeaderFrameX, newHeaderFrameY = frame.startHeaderFrameX + deltaMouseX, frame.startHeaderFrameY + deltaMouseY
			
			ObjectiveTrackerFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", newBkgFrameX,  newBkgFrameY)
			ObjectiveTrackerFrame.HeaderMenu:ClearAllPoints()
			ObjectiveTrackerFrame.HeaderMenu:SetPoint("TOPLEFT", UIParent, "TOPLEFT", newHeaderFrameX,  newHeaderFrameY)
			
			lastTrackerX, lastTrackerY = GUIUtils:GetRealFeamePos(ObjectiveTrackerFrame)
		end
	end
end

WF.OnFrameUpdate = function()
	if not WF.initialized then
		return
	end
	
	local SmallFrame = GetSmallFrame()
	
	if SmallFrame and SmallFrame.Frame and not DGV:IsGoldMode() then
		SmallFrame.header:Hide()
		SmallFrame.Frame:Hide()
	end
	
	if SmallFrame and SmallFrame.Frame:GetTop() == nil then
		local initialY = -180
		local initialX = GetScreenWidth() - 350
		SmallFrame.Frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", initialX, initialY)
	end
	
	--Setting original Objective Tracker/small frame position (below minimap) in case SmallFrame/Objective frame is not floating
	if not DugisGuideViewer:UserSetting(DGV_MOVEWATCHFRAME) then
	
		--Checking space for action bars
		local marginRight  = 0
		local marginTop = 0

		if MultiBarLeft:IsVisible() then
			marginRight = MultiBarLeft:GetWidth() * 2
		else
			if MultiBarRight:IsVisible() then
				marginRight = MultiBarRight:GetWidth()
			end
		end
		
		local top = MinimapCluster:GetHeight()
		
		if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
			if DurabilityFrame and DurabilityFrame:IsVisible() then
				marginTop = -DurabilityFrame:GetHeight() - 10
			end
			
			if VehicleSeatIndicator and VehicleSeatIndicator:IsVisible() then
				marginTop = -VehicleSeatIndicator:GetHeight() - 10
			end
		
			ObjectiveTrackerFrame:ClearAllPoints()
			ObjectiveTrackerFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", GetScreenWidth() - ObjectiveTrackerFrame:GetWidth() - 25 - marginRight - 5, -top + marginTop)
		else
			if DurabilityFrame and DurabilityFrame:IsVisible() then
				marginTop = -DurabilityFrame:GetHeight() + 5
			end
			
			if VehicleSeatIndicator and VehicleSeatIndicator:IsVisible() then
				marginTop = -VehicleSeatIndicator:GetHeight() + 5
			end
			
			SmallFrame.Frame:ClearAllPoints()
			SmallFrame.Frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", GetScreenWidth() - SmallFrame.Frame:GetWidth() - marginRight - 5, -top + marginTop)		
		end
	end
	
	local left, top = 0,0
	
	if DGV:IsGoldMode() then
		 left, top = GUIUtils:GetRealFeamePos(SmallFrame.Frame)
	end
	
	local leftTracker, topTracker = GUIUtils:GetRealFeamePos(ObjectiveTrackerFrame)
	
	if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
		ObjectiveTrackerFrame:ClearAllPoints()
		
		--Preventing reseting Objective Frame position to the original one
		if DugisGuideViewer:UserSetting(DGV_MOVEWATCHFRAME) and leftTracker then
			ObjectiveFrameDugiBkg:SetPoint("TOPLEFT", UIParent, "TOPLEFT", leftTracker - 40,  topTracker + 15)
			ObjectiveTrackerFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", leftTracker,  topTracker)
		else
			ObjectiveFrameDugiBkg:SetPoint("TOPLEFT", UIParent, "TOPLEFT", leftTracker - 40,  topTracker + 15)
			ObjectiveTrackerFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", leftTracker,  topTracker)
			lastTrackerX, lastTrackerY = leftTracker, topTracker
		end
		
		ObjectiveTrackerFrame:SetHeight(GetScreenHeight())
	else
		local height =  SmallFrame.Frame:GetHeight()
		
		if DGV.shouldUpdateObjectiveTracker then 
			ObjectiveTrackerFrame:ClearAllPoints()
			ObjectiveTrackerFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left + 40,  top - height)
			ObjectiveTrackerFrame:SetHeight(GetScreenHeight())
		end
		ObjectiveFrameDugiBkg:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left,  top - height + 10)
	end
	
	local width = 300
	if DGV:IsGoldMode() then
		width = SmallFrame.Frame:GetWidth()
	end
	ObjectiveFrameDugiBkg:SetWidth(width)
	
	if GetWorldQuestRealHeight() then
		ObjectiveFrameDugiBkg:SetHeight(GetWorldQuestRealHeight() + 30)
	end
	
	ObjectiveFrameDugiBkg.initialized = true
	
	
	if DGV:IsGoldMode() then
		--SmallFrameBkg
		SmallFrameBkg:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left,  top)
		SmallFrameBkg:SetWidth(width)
		
		if  smallAndObjectiveFrameOneBkg and not SmallFrame.IsFloating() then 
			local _, topTracker = GUIUtils:GetRealFeamePos(ObjectiveFrameDugiBkg)
			local heightTracker = ObjectiveFrameDugiBkg:GetHeight()
			local bottomTracker = topTracker - heightTracker
			local heightSharedBkg = 0
			
			if IsObjectiveTrackerVisible() then
				heightSharedBkg = top - bottomTracker
			else
				heightSharedBkg = SmallFrame.Frame:GetHeight()
			end
			
			SmallFrameBkg:SetHeight(heightSharedBkg)
		else
			SmallFrameBkg:SetHeight(SmallFrame.Frame:GetHeight())
		end
		
		--Visibility
		if SmallFrame.Frame:IsVisible() and not IsSmallFrameCollapsed() then
			SmallFrameBkg:Show()
		else
			SmallFrameBkg:Hide()
		end
	else
		if SmallFrameBkg then
			SmallFrameBkg:Hide()
		end
	end
	
	ObjectiveFrameDugiBkgDrag()
	
	if DGV:IsGoldMode() then
		--Updating small frame header positioning
		if SmallFrame.Frame:IsVisible() and not IsSmallFrameCollapsed() then
			SmallFrame.header:Show()
			
			SmallFrame.header:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left + 30,  top - 10)
			SmallFrame.header:EnableMouse(false)
			--SmallFrame.header.Text:EnableMouse(false)

		else
			SmallFrame.header:Hide()
		end
	end
	---
	if ObjectiveFrameDugiBkg then
		local shouldBeHidden = not ObjectiveTrackerFrame.HeaderMenu:IsVisible()  or ObjectiveTrackerFrame.collapsed  or not ObjectiveFrameDugiBkg.initialized 
		
		if DGV.shouldUpdateObjectiveTracker then
			if shouldBeHidden then
				ObjectiveFrameDugiBkg:Hide()
			else
				ObjectiveFrameDugiBkg:Show()
			end
		end
		
		if shouldBeHidden
		or (smallAndObjectiveFrameOneBkg and (DGV:IsGoldMode() and not SmallFrame.IsFloating()) )then 
			ObjectiveFrameDugiBkg:SetAlpha(0)
		else
			ObjectiveFrameDugiBkg:SetAlpha(1)
		end
	end
	
	--Updating header menu ( [V] button positon)
	if DGV.shouldUpdateObjectiveTracker then 
		ObjectiveTrackerFrame.HeaderMenu:ClearAllPoints()
		if not DGV:IsGoldMode() or SmallFrame.IsFloating() then
			local width = ObjectiveFrameDugiBkg:GetWidth()
			ObjectiveTrackerFrame.HeaderMenu:SetPoint("TOPLEFT", UIParent, "TOPLEFT", leftTracker + width - 60,  topTracker)	
		else
			ObjectiveTrackerFrame.HeaderMenu:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left + width - 20,  top - 10)	
		end
		
		if SmallFrameBkg then
			SmallFrameBkg:SetAlpha(1)
		end
	end
	
	-----Model viewer
	-- MV.Frame.moving
	if DugisGuideViewer.Modules.ModelViewer then
		local MV = DugisGuideViewer.Modules.ModelViewer
		if MV.Frame then
			local width = MV.Frame:GetWidth()
			if DGV:UserSetting(DGV_LOCKMODELFRAME) then 
				if not InCombatLockdown() then
					MV.Frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", left - width + 7, top)
				end
			end
		end
	end
	
	--Checking if only small frame is visible. If that is the case then an extra header button should be shown
	if SmallFrame then
		SmallFrame.UpdateSmallFrameHeader()
		SmallFrame.UpdateProgressBarPosition()
	end
end

function WF:UpdateWatchFrameMovable()
	if DugisGuideViewer:UserSetting(DGV_DISABLEWATCHFRAMEMOD) then 
		ObjectiveFrameDugiBkg:EnableMouse(false)
	else 
		ObjectiveFrameDugiBkg:EnableMouse(true)
	end
		
	local SmallFrame = GetSmallFrame()
		
	if SmallFrame then
		SmallFrame.Frame:EnableMouse(not DugisGuideViewer:UserSetting(DGV_LOCKSMALLFRAME))
		SmallFrame.collapseHeader:EnableMouse(not DugisGuideViewer:UserSetting(DGV_LOCKSMALLFRAME))
		if DugisSmallFrameStatus1 then
			DugisSmallFrameStatus1:EnableMouse(not DugisGuideViewer:UserSetting(DGV_LOCKSMALLFRAME))
		end
	end
end   

function WF:Initialize()  
	if WF.initialized then return end
	WF.initialized = true
  
    function WF:ResetWatchFrameMovable()
        WF:DelayUpdate()
	end    
    

	local flashGroup, flash
	local L, RegisterFunctionReaction, RegisterMemberFunctionReaction = DugisLocals, DGV.RegisterFunctionReaction, DGV.RegisterMemberFunctionReaction
	
	function WF:ShouldModWatchFrame(forceLoaded)
		if forceLoaded then return true end
		return not IncompatibleAddonLoaded() and (WF.loaded or forceLoaded)
	end

	function WF:Reset()
	end
	
    function GetLastWorldQuestBlock()
        local bottomBlock = nil
        local top = 100000
         
        LuaUtils:foreach(WORLD_QUEST_TRACKER_MODULE.usedBlocks, function(v, k) 
            if (v:GetTop() and v:GetTop() < top)  or (v:GetBottom() and v:GetBottom() < top)then
                bottomBlock = v
                top = v:GetTop()
            end
        end) 
         
        return bottomBlock
    end
    
	local function GetBottomElement()
		if GetNumTrackedAchievements() > 0 then 
			return ACHIEVEMENT_TRACKER_MODULE.lastBlock
		elseif C_Scenario.GetInfo() then 
            if ObjectiveTrackerBlocksFrame.QuestHeader.module.lastBlock == nil then
                return ACHIEVEMENT_TRACKER_MODULE.lastBlock
            end
			return ObjectiveTrackerBlocksFrame.QuestHeader.module.lastBlock
        elseif GetLastWorldQuestBlock() then
            return GetLastWorldQuestBlock()
        else
			return BONUS_OBJECTIVE_TRACKER_MODULE.firstBlock or ObjectiveTrackerBlocksFrame.QuestHeader.module.lastBlock or ObjectiveTrackerBlocksFrame
		end
	end
	
	function GetWorldQuestRealHeight()
		local lastBlock = GetBottomElement()
		if lastBlock then
			local height = lastBlock:GetHeight()
			local top = (GetScreenHeight()  - lastBlock:GetTop())
			local ObjectiveTrackerFrame_top = (GetScreenHeight()  - ObjectiveTrackerFrame:GetTop())
			local realHeight = top -  ObjectiveTrackerFrame_top + height
			return realHeight
		end
	end
	
	local firstTime = true
	function WF:DelayUpdate()
		if DugisGuideViewer:IsModuleRegistered("SmallFrame") then 
			DGV:OnWatchFrameUpdate() 
			if firstTime then
				LuaUtils:Delay(2, function()
					DGV:OnWatchFrameUpdate() 
				end)
			end
			firstTime = false
		else
			LuaUtils:Delay(2, function()
				if DugisGuideViewer:IsModuleRegistered("SmallFrame") then 
					DGV:OnWatchFrameUpdate() 
				end
			end)
		end
	end

	local objectiveTrackerUpdateReaction--, manageFramePositionsReaction
	function WF:Load()
		objectiveTrackerUpdateReaction = RegisterFunctionReaction("ObjectiveTracker_Update", nil, WF.DelayUpdate)
	end

	function WF:Unload()
		objectiveTrackerUpdateReaction:Dispose()
	end
	
	if IsAddOnLoaded("DBM-Core") and DugisGuideViewer:GuideOn() and DugisGuideViewer.chardb.EssentialsMode ~= 1 then 
		hooksecurefunc(DBM, "StartCombat", function()
			DGV:OnDBMUpdate()
		end)	
		hooksecurefunc(DBM, "EndCombat", function()
			DGV:OnDBMUpdate()
		end)		
	end
end
