require(game.ReplicatedFirst.ReadyModule)
local module = {}
local input = game:GetService("UserInputService")
local mouse = require(_G.Modules.MouseModule)

local gamepad = Enum.UserInputType.Gamepad1
local function KeyBinding(keycode,value)
	return function()
		if input:IsKeyDown(keycode) then return value else return nil end
	end
end
local function ButtonBinding(keycode,value)
	return function()
		if input:IsGamepadButtonDown(gamepad,keycode) then return value else return nil end
	end
end
local function MouseBinding(inputtype,value)
	return function()
		if input:IsMouseButtonPressed(inputtype) then return value else return nil end
	end
end

local function SequenceBinding(iterations,predicate)
	local value = 0
	input.InputEnded:Connect(function(input,irrelevant)
		if not irrelevant then
			if predicate(input) then
				value = value + 1/iterations
				if value > 1 then value = 0 end
				return value
			end
		end
	end)
	return function() return value end
end

local function SequenceKeyBinding(keycode,iterations)
	return SequenceBinding(iterations,function(input)
		return input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == keycode
	end)
end
local function SequenceButtonBinding(keycode,iterations)
	return SequenceBinding(iterations,function(input)
		return input.UserInputType == gamepad and input.KeyCode == keycode
	end)
end
local function SequenceMouseBinding(inputtype,iterations)
	return SequenceBinding(iterations,function(input)
		return input.UserInputType == inputtype
	end)
end

local function HoldBinding()
	return function(old,new)
		if not new then return old end
	end
end

local function DeltaBinding(velocity,predicate)
	return function(value,new,delta)
		if predicate() then return (value or 0) + velocity * delta end
	end
end
	
local function DeltaKeyBinding(keycode,velocity)
	return DeltaBinding(velocity,function()
		return input:IsKeyDown(keycode)
	end)
end
local function DeltaButtonBinding(keycode,velocity)
	return DeltaBinding(velocity,function()
		return input:IsGamepadButtonDown(gamepad,keycode)
	end)
end
local function DeltaMouseBinding(inputtype,velocity)
	return DeltaBinding(velocity,function()
		return input:IsMouseButtonPressed(inputtype)
	end)
end

local function MouseMovement(keycode)
	return function()
		input:IsKeyDown(keycode) 
	end
end

local controlBindings = {
	throttle = {
		DeltaKeyBinding(Enum.KeyCode.LeftShift,1),
		DeltaKeyBinding(Enum.KeyCode.LeftControl,-1),
		HoldBinding()
	},
	pitch = {
		KeyBinding(Enum.KeyCode.W,-1),
		KeyBinding(Enum.KeyCode.S,1)
	},
	yaw = {
		KeyBinding(Enum.KeyCode.Q,1),
		KeyBinding(Enum.KeyCode.E,-1)
	},
	roll = {
		KeyBinding(Enum.KeyCode.A,1),
		KeyBinding(Enum.KeyCode.D,-1)
	},
	fire = {
		MouseBinding(Enum.UserInputType.MouseButton1,1),
		KeyBinding(Enum.KeyCode.F,-1)
	},
	bomb = {
		KeyBinding(Enum.KeyCode.B,1)
	},
	action1 = {
		ButtonBinding(Enum.KeyCode.L,1)
	},
	action2 = {
		MouseBinding(Enum.UserInputType.MouseButton3,1)
	},
	flaps = {
		SequenceKeyBinding(Enum.KeyCode.F,4)
	},
	gear = {
		SequenceKeyBinding(Enum.KeyCode.G,1)
	},
}

module.values = {}
module.cursor = nil

function module.aimTowards(root,position,values)
	local aim = root:PointToObjectSpace(position).Unit
	local _,_,z = root:ToEulerAnglesYXZ()
	values.pitch += aim.Y*2 + values.pitch
	values.yaw += aim.X*-2 + values.yaw
	values.roll += values.roll + (-z/3) + values.yaw/5
end

-- Bindings
local shouldAim = true
module.seat = nil
if _G.IsClient then
	spawn(function()
		local dragger = require(_G.Modules.DraggingModule).dragger
		_G:WaitFor("ControlMouseButton")
		local function aimOptionCallback()
			shouldAim = not shouldAim
			if shouldAim then 
				_G.ControlMouseButton.Text = "Mouse"
			else
				_G.ControlMouseButton.Text = "WASD"
			end
		end
		_G.ControlMouseButton.Activated:Connect(aimOptionCallback)
		input.InputEnded:Connect(function(input,irrelevant)
			if not irrelevant then
				if 
					input.UserInputType == Enum.UserInputType.Keyboard and 
					input.KeyCode == Enum.KeyCode.LeftAlt 
				then
					aimOptionCallback()
				end
			end
		end)
		local function processThrottle(throttle)
			throttle = math.clamp(throttle,-1,1)
			_G.ThrottleFrame.ThrottleBar.Value.Size = UDim2.new(1, 0, 0.5 * math.abs(throttle),0)
			_G.ThrottleFrame.ThrottleBar.Value.Position = UDim2.new(0, 0, 0.5 - (0.5 * math.clamp(throttle,0,1)),0)
			_G.ThrottleFrame.TextValue.Text = tostring(math.ceil(throttle * 100)).."%"
			if throttle > 0 then
				_G.ThrottleFrame.ThrottleBar.Value.BackgroundColor3 = Color3.new(0, 1, 0)
			end
			if throttle < 0 then
				_G.ThrottleFrame.ThrottleBar.Value.BackgroundColor3 = Color3.new(1, 0, 0)
			end
			module.values.throttle = throttle
		end
		dragger(_G.ThrottleFrame.ThrottleBar,function(begin)
			return {
				drag = function(changed)
					local down = (changed.Y - (_G.ThrottleFrame.ThrottleBar.AbsolutePosition.Y))/_G.ThrottleFrame.ThrottleBar.AbsoluteSize.Y
					processThrottle(-(math.clamp(down,0,1) * 2 - 1))
				end,
			}
		end)
		repeat
			local delta = task.wait()
			_G.ThrottleFrame.Visible = not not module.seat
			if not module.seat then continue end
			for name,bindings in pairs(controlBindings) do
				local value = nil
				for _,binding in pairs(bindings) do
					local new = binding(module.values[name],value,delta)
					if new then
						--print(name,module.values[name],value,delta)
						if math.abs(new) > (value or 0) then value = new end
					end
				end
				module.values[name] = value or 0
			end
			local instance,ray = mouse.getMouseHit()
			module.cursor = ray.Origin + ray.Direction * 300
			if module.seat and shouldAim then
				local position = ray.Origin + ray.Direction * 300 + Vector3.new(0,25,0)
				module.aimTowards(module.seat:GetPivot(),position,module.values)
			end
			processThrottle(module.values.throttle)
			for index,value in pairs(module.values) do
				module.values[index] = math.clamp(value or 0,-1,1)
			end
		until false
	end)
end

return module