--!nonstrict
local PlayersService = game:GetService('Players')

-- When PlayerScripts are loaded, sibling scripts and folders with the same name are merged
local RootCameraCreator = require(script.Parent) :: typeof(require(script.Parent.Parent.RootCamera))

local ZERO_VECTOR2 = Vector2.new(0, 0)
local XZ_VECTOR = Vector3.new(1,0,1)

local Vector2_new = Vector2.new
local CFrame_new = CFrame.new
local math_atan2 = math.atan2
local math_min = math.min

local function IsFinite(num)
	return num == num and num ~= 1/0 and num ~= -1/0
end

-- May return NaN or inf or -inf
-- This is a way of finding the angle between the two vectors:
local function findAngleBetweenXZVectors(vec2, vec1)
	return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z)
end

local function CreateAttachCamera()
	local module = RootCameraCreator()

	local lastUpdate = tick()
	function module:Update()
		local now = tick()

		local camera = 	workspace.CurrentCamera

		if lastUpdate == nil or now - lastUpdate > 1 then
			module:ResetCameraLook()
			self.LastCameraTransform = nil
		end

		local subjectPosition = self:GetSubjectPosition()
		if subjectPosition and camera then
			local zoom = self:GetCameraZoom()
			if zoom <= 0 then
				zoom = 0.1
			end


			local humanoid = self:GetHumanoid()
			if lastUpdate and humanoid and humanoid.Torso then

				-- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
				local delta = math_min(0.1, now - lastUpdate)
				local gamepadRotation = self:UpdateGamepad()
				self.RotateInput = self.RotateInput + (gamepadRotation * delta)

				local forwardVector = humanoid.Torso.CFrame.lookVector

				local y = findAngleBetweenXZVectors(forwardVector, self:GetCameraLook())
				if IsFinite(y) then
					-- Preserve vertical rotation from user input
					self.RotateInput = Vector2_new(y, self.RotateInput.Y)
				end
			end

			local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput)
			self.RotateInput = ZERO_VECTOR2

			camera.Focus = CFrame_new(subjectPosition)
			local newCFrame = CFrame_new(subjectPosition - (zoom * newLookVector), subjectPosition)
			camera.CFrame = newCFrame
			self.LastCameraTransform = newCFrame
		end
		lastUpdate = now
	end

	return module
end

return CreateAttachCamera
