-- Luke


local uis = game:GetService('UserInputService')
local tweenService = game:GetService('TweenService')
local runService = game:GetService('RunService')
local playersService = game:GetService('Players')
local localPlayer = playersService.LocalPlayer
local gui = script:WaitForChild('TokenTransitionGui')
local viewportFrame = gui:WaitForChild('ViewportFrame')
local tokenModel = viewportFrame:WaitForChild('Token')
local glowPart = viewportFrame:WaitForChild('GlowPart')
local glowDecal = glowPart:WaitForChild('GlowDecal')
local background = gui:WaitForChild('Background')
local sound = gui:WaitForChild('FlySound')

local camera = Instance.new('Camera')
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = CFrame.new(0,0,0)
camera.FieldOfView = 40
camera.Parent = viewportFrame
viewportFrame.CurrentCamera = camera

local DISABLE_TIME = 3

local TOKEN_SPIN_RATE = -.25
local CLICK_VELOCITY = .3
local SPIN_DAMPER = .15
local MAX_SPEED = 1.5

local ICON_FADE_IN_TIME = 2
local ICON_FADE_OUT_TIME = 3


local rng = Random.new()
local qpi = math.pi*.5
local tau = math.pi*2


local enabled = false
local changeIndex = 0
local renderstepBound = false
local inputConnection = nil
local requestedBadge = false


local tokenOriginalCF = tokenModel.PrimaryPart.CFrame
local tokenPartCFrames = {}
for _,child in pairs(tokenModel:GetDescendants()) do
	if child:IsA("BasePart") and child ~= tokenModel.PrimaryPart then
		tokenPartCFrames[child] = child.CFrame:ToObjectSpace(tokenModel.PrimaryPart.CFrame)
	end
end

local spin = 0
local spinVelocity = 0
function spinToken(delta)
	--local spin = os.clock()*tau*TOKEN_SPIN_RATE
	spin = (spin + delta*tau*(TOKEN_SPIN_RATE+spinVelocity))%tau
	if math.abs(spinVelocity) < delta*SPIN_DAMPER then
		spinVelocity = 0
	else
		spinVelocity = spinVelocity - delta * SPIN_DAMPER * math.sign(spinVelocity)
	end
	
	local newCFrame = tokenOriginalCF * CFrame.Angles(0, spin, 0)
	tokenModel.PrimaryPart.CFrame = newCFrame
	for tokenModelPart, cframeOffset in pairs(tokenPartCFrames) do
		tokenModelPart.CFrame = newCFrame * cframeOffset
	end
	
	local glownessPercent = math.sin(spin*2+qpi)*.5+.5
	glowDecal.Transparency = .75+.1*(1-glownessPercent)
	local width = 7.5+1*glownessPercent
	glowPart.Size = Vector3.new(width, .01, width)
end


function requestBadge()
	if not requestedBadge then	--TODO: replace with a debounce timer
		requestedBadge = true
		--TODO: request badge
	end
end

function spinAction(direction)
	spinVelocity = math.clamp(spinVelocity + CLICK_VELOCITY*direction, -MAX_SPEED, MAX_SPEED)
	requestBadge()
end

local leftControls = {
	[Enum.KeyCode.DPadLeft] = true,
	[Enum.KeyCode.ButtonL1] = true,
	[Enum.KeyCode.A] = true,
	[Enum.KeyCode.Left] = true,
}
local rightControls = {
	[Enum.KeyCode.DPadRight] = true,
	[Enum.KeyCode.ButtonR1] = true,
	[Enum.KeyCode.D] = true,
	[Enum.KeyCode.Right] = true,
}
function handleInput(input, processed)
	if input and input.UserInputState == Enum.UserInputState.Begin then
		if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
			local direction = math.sign(input.Position.X - viewportFrame.AbsoluteSize.X*.5)
			spinAction(direction)
		elseif input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Keyboard then
			if leftControls[input.KeyCode] then
				spinAction(-1)
			elseif rightControls[input.KeyCode] then
				spinAction(1)
			end
		end
	end
end


function enable(spinControl)
	local playerGui = localPlayer:FindFirstChild('PlayerGui')
	if not enabled and playerGui then
		enabled = true
		changeIndex = changeIndex + 1
		local thisChangeIndex = changeIndex
		if not gui.Enabled then
			spin = tau*.9	-- Initial rotation
			spinVelocity = 0
			background.BackgroundTransparency = 1
			camera.CFrame = CFrame.new(-7,0,-10)
		end
		viewportFrame.ImageTransparency = 0
		viewportFrame.Visible = true
		gui.Parent = playerGui
		gui.Enabled = true
		sound.PlaybackSpeed = .5
		sound.Volume = .5
		sound:Play()
		
		if not renderstepBound then
			renderstepBound = true
			runService:BindToRenderStep('TokenTransition', Enum.RenderPriority.Camera.Value-1, spinToken)
		end
		
		tweenService:Create(sound,
			TweenInfo.new(DISABLE_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['Volume'] = .5,}
		):Play()
		tweenService:Create(viewportFrame,
			TweenInfo.new(.1, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['ImageTransparency'] = 0,}
		):Play()
		tweenService:Create(camera,
			TweenInfo.new(1.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
			{['CFrame'] = CFrame.new(0,0,-10),}
		):Play()
		task.delay(1.5, function()
			if thisChangeIndex == changeIndex then
				if inputConnection then
					inputConnection:Disconnect()
					inputConnection = nil
				end
				if spinControl then
					inputConnection = uis.InputBegan:connect(handleInput)
				end
				tweenService:Create(background,
					TweenInfo.new(.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
					{['BackgroundTransparency'] = 0,}
				):Play()
				tweenService:Create(camera,
					TweenInfo.new(4, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
					{['CFrame'] = CFrame.new(0,0,0),}
				):Play()
			end
		end)
	end
end

function disable()
	local playerGui = localPlayer:FindFirstChild('PlayerGui')
	if enabled and playerGui then
		enabled = false
		changeIndex = changeIndex + 1
		local thisChangeIndex = changeIndex
		if inputConnection then
			inputConnection:Disconnect()
			inputConnection = nil
		end

		sound.PlaybackSpeed = .5
		sound:Play()
		tweenService:Create(sound,
			TweenInfo.new(DISABLE_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['Volume'] = 0,}
		):Play()
		tweenService:Create(camera,
			TweenInfo.new(DISABLE_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['CFrame'] = CFrame.new(0,0,300),}
		):Play()
		tweenService:Create(background,
			TweenInfo.new(DISABLE_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['BackgroundTransparency'] = 1,}
		):Play()
		tweenService:Create(viewportFrame,
			TweenInfo.new(DISABLE_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{['ImageTransparency'] = 1,}
		):Play()
		task.delay(DISABLE_TIME, function()
			if thisChangeIndex == changeIndex then
				for _,iconLabel in pairs(gui:GetChildren()) do
					if iconLabel and iconLabel.Parent and iconLabel.Name == 'CleaningUpIcon' or iconLabel.Name == 'Icon' then
						iconLabel:Destroy()
					end
				end
				gui.Enabled = false
				gui.ViewportFrame.Visible = false
				gui.Parent = script
				if not renderstepBound then
					renderstepBound = false
					runService:UnbindFromRenderStep('TokenTransition')
				end
			end
		end)
	end
end


local module = {
	Enable = enable,
	Disable = disable,
}

return module