--- Returns the target within the current scope based on the current targeting mode.
-- @param Target Which part is being targeted directly
-- @param Scope The current scope to search for the target in
-- @returns Instance | nil

function TargetingModule:FindTargetInScope(Target, Scope)

	-- Return `nil` if no target, or if scope is unset
	if not (Target and Scope) then
		return nil
	end

	-- If in direct targeting mode, return target
	if self.TargetingMode == 'Direct' and (Target:IsDescendantOf(Scope)) then
		return Target
	end

	-- Search for ancestor of target directly within scope
	local TargetChain = { Target }
	while Target and (Target.Parent ~= Scope) do
		table.insert(TargetChain, 1, Target.Parent)
		Target = Target.Parent
	end

	-- Return targetable ancestor closest to scope
	for Index, Target in ipairs(TargetChain) do
		if IsTargetable(Target) then
			return Target
		end
	end

end

function TargetingModule:UpdateTarget(Scope, Force)
	local Scope = Scope or self.Scope

	-- Get target
	local NewTarget = Mouse.Target
	local NewScopeTarget = self:FindTargetInScope(NewTarget, Scope)

	-- Register whether target has changed
	if (self.LastTarget == NewTarget) and (not Force) then
		return NewTarget, NewScopeTarget
	else
		self.LastTarget = NewTarget
		self.TargetChanged:Fire(NewTarget)
	end

	-- Make sure target is selectable
	local Core = GetCore()
	if not Core.IsSelectable({ NewTarget }) then
		self.HighlightTarget(nil)
		self.LastTarget = nil
		self.LastScopeTarget = nil
		self.TargetChanged:Fire(nil)
		self.ScopeTargetChanged:Fire(nil)
		return
	end

	-- Register whether scope target has changed
	if (self.LastScopeTarget == NewScopeTarget) and (not Force) then
		return NewTarget, NewScopeTarget
	else
		self.LastScopeTarget = NewScopeTarget
		self.ScopeTargetChanged:Fire(NewScopeTarget)
	end

	-- Update scope target highlight
	if not Core.Selection.IsSelected(NewScopeTarget) then
		self.HighlightTarget(NewScopeTarget)
	end

	-- Return new targets
	return NewTarget, NewScopeTarget
end

local function GetVisibleChildren(Item, Table)
	local Table = Table or {}

	-- Search for visible items recursively
	for _, Item in pairs(Item:GetChildren()) do
		if IsVisible(Item) then
			Table[#Table + 1] = Item
		else
			GetVisibleChildren(Item, Table)
		end
	end

	-- Return visible items
	return Table
end
