-- Camera mod

local Camera = require(cameraModule)

local lastUpCFrame = IDENTITYCF

Camera.UpVector = Vector3.new(0, 1, 0)
Camera.TransitionRate = 0.15
Camera.UpCFrame = IDENTITYCF

Camera.SpinPart = TERRAIN
Camera.LastSpinPart = TERRAIN
Camera.LastSpinCFrame = TERRAIN.CFrame
Camera.SpinCFrame = IDENTITYCF

function Camera:GetUpVector(oldUpVector)
	return oldUpVector
end

function Camera:CalculateUpCFrame()
	local oldUpVector = self.UpVector
	local newUpVector = self:GetUpVector(oldUpVector)
	
	local backup = game.Workspace.CurrentCamera.CFrame.RightVector
	local transitionCF = getRotationBetween(oldUpVector, newUpVector, backup)
	local vecSlerpCF = IDENTITYCF:Lerp(transitionCF, self.TransitionRate)
	
	self.UpVector = vecSlerpCF * oldUpVector
	self.UpCFrame = vecSlerpCF * self.UpCFrame
	
	lastUpCFrame = self.UpCFrame
end

function Camera:SetSpinPart(part)
	self.SpinPart = part
end

function Camera:CalculateSpinCFrame()
	local delta = 0
	local part = self.SpinPart
	
	if (part == self.LastSpinPart) then
		local lastCF = self.LastSpinCFrame
	
		local rotation = part.CFrame - part.CFrame.p
		local prevRotation = lastCF - lastCF.p
		
		local direction = rotation:VectorToObjectSpace(self.UpVector)
		delta = twistAngle(prevRotation:ToObjectSpace(rotation), direction)
	end
	
	self.SpinCFrame = CFrame.fromEulerAnglesYXZ(0, delta, 0)
	self.LastSpinPart = part
	self.LastSpinCFrame = part.CFrame
end

function Camera:Update(dt)
	if self.activeCameraController then
		if Camera.FFlagUserCameraToggle then
			self.activeCameraController:UpdateMouseBehavior()
		end
		
		local newCameraCFrame, newCameraFocus = self.activeCameraController:Update(dt)
		self.activeCameraController:ApplyVRTransform()
		
		self:CalculateUpCFrame()
		self:CalculateSpinCFrame()
		self.activeCameraController:UpdateUpCFrame(self.UpCFrame)
		
		-- undo shift-lock offset

		local lockOffset = Vector3.new(0, 0, 0)
		if (self.activeMouseLockController and self.activeMouseLockController:GetIsMouseLocked()) then
			lockOffset = self.activeMouseLockController:GetMouseLockOffset()
		end
		
		local offset = newCameraFocus:ToObjectSpace(newCameraCFrame)
		local camRotation = self.UpCFrame * self.SpinCFrame * offset
		newCameraFocus = newCameraFocus - newCameraCFrame:VectorToWorldSpace(lockOffset) + camRotation:VectorToWorldSpace(lockOffset)
		newCameraCFrame = newCameraFocus * camRotation
		
		--local offset = newCameraFocus:Inverse() * newCameraCFrame
		--newCameraCFrame = newCameraFocus * self.UpCFrame * offset
		
		if (self.activeCameraController.lastCameraTransform) then
			self.activeCameraController.lastCameraTransform = newCameraCFrame
			self.activeCameraController.lastCameraFocus = newCameraFocus
		end
		
		if self.activeOcclusionModule then
			newCameraCFrame, newCameraFocus = self.activeOcclusionModule:Update(dt, newCameraCFrame, newCameraFocus)
		end

		game.Workspace.CurrentCamera.CFrame = newCameraCFrame
		game.Workspace.CurrentCamera.Focus = newCameraFocus

		if self.activeTransparencyController then
			self.activeTransparencyController:Update()
		end
	end
end

function Camera:IsFirstPerson()
	if self.activeCameraController then
		return self.activeCameraController:InFirstPerson()
	end
	return false
end

function Camera:IsMouseLocked()
	if self.activeCameraController then
		return self.activeCameraController:GetIsMouseLocked()
	end
	return false
end

function Camera:IsToggleMode()
	if self.activeCameraController then
		return self.activeCameraController.isCameraToggle
	end
	return false
end

function Camera:IsCamRelative()
	return self:IsMouseLocked() or self:IsFirstPerson()
	--return self:IsToggleMode(), self:IsMouseLocked(), self:IsFirstPerson()
end