local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer
local camera = workspace.CurrentCamera

--==================================================
-- CONFIGURACIÓN
--=================================================

local CAMERA_SPEED = 50
local FAST_CAMERA_SPEED = 150

local MOUSE_SENSITIVITY = 0.003

--==================================================
-- VARIABLES
--==================================================

local character
local humanoid
local rootPart

local cameraPosition = Vector3.zero

local yaw = 0
local pitch = 0

local rightMouseDown = false

local keys = {
	W = false,
	A = false,
	S = false,
	D = false,

	I = false,
	J = false,
	K = false,
	L = false,

	U = false,
	O = false,

	Shift = false
}

--==================================================
-- PERSONAJE
--==================================================

local function setupCharacter(char)
	character = char
	humanoid = char:WaitForChild("Humanoid")
	rootPart = char:WaitForChild("HumanoidRootPart")

	-- La cámara NO seguirá al personaje
	camera.CameraType = Enum.CameraType.Scriptable

	-- La cámara empieza donde estaba el personaje
	cameraPosition = rootPart.Position + Vector3.new(0, 5, 15)

	-- Mirar hacia el personaje inicialmente
	local direction = rootPart.Position - cameraPosition

	yaw = math.atan2(-direction.X, -direction.Z)
	pitch = math.asin(
		math.clamp(direction.Unit.Y, -1, 1)
	)
end

player.CharacterAdded:Connect(setupCharacter)

if player.Character then
	setupCharacter(player.Character)
end

--==================================================
-- TECLAS
--==================================================

UserInputService.InputBegan:Connect(function(input, processed)
	if processed then
		return
	end

	if input.UserInputType == Enum.UserInputType.Keyboard then

		if input.KeyCode == Enum.KeyCode.W then
			keys.W = true

		elseif input.KeyCode == Enum.KeyCode.A then
			keys.A = true

		elseif input.KeyCode == Enum.KeyCode.S then
			keys.S = true

		elseif input.KeyCode == Enum.KeyCode.D then
			keys.D = true

		elseif input.KeyCode == Enum.KeyCode.I then
			keys.I = true

		elseif input.KeyCode == Enum.KeyCode.J then
			keys.J = true

		elseif input.KeyCode == Enum.KeyCode.K then
			keys.K = true

		elseif input.KeyCode == Enum.KeyCode.L then
			keys.L = true

		elseif input.KeyCode == Enum.KeyCode.U then
			keys.U = true

		elseif input.KeyCode == Enum.KeyCode.O then
			keys.O = true

		elseif input.KeyCode == Enum.KeyCode.LeftShift
			or input.KeyCode == Enum.KeyCode.RightShift then

			keys.Shift = true
		end
	end

	-- Botón derecho del mouse
	if input.UserInputType == Enum.UserInputType.MouseButton2 then
		rightMouseDown = true

		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
	end
end)

UserInputService.InputEnded:Connect(function(input)

	if input.UserInputType == Enum.UserInputType.Keyboard then

		if input.KeyCode == Enum.KeyCode.W then
			keys.W = false

		elseif input.KeyCode == Enum.KeyCode.A then
			keys.A = false

		elseif input.KeyCode == Enum.KeyCode.S then
			keys.S = false

		elseif input.KeyCode == Enum.KeyCode.D then
			keys.D = false

		elseif input.KeyCode == Enum.KeyCode.I then
			keys.I = false

		elseif input.KeyCode == Enum.KeyCode.J then
			keys.J = false

		elseif input.KeyCode == Enum.KeyCode.K then
			keys.K = false

		elseif input.KeyCode == Enum.KeyCode.L then
			keys.L = false

		elseif input.KeyCode == Enum.KeyCode.U then
			keys.U = false

		elseif input.KeyCode == Enum.KeyCode.O then
			keys.O = false

		elseif input.KeyCode == Enum.KeyCode.LeftShift
			or input.KeyCode == Enum.KeyCode.RightShift then

			keys.Shift = false
		end
	end

	if input.UserInputType == Enum.UserInputType.MouseButton2 then
		rightMouseDown = false

		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	end
end)

--==================================================
-- MOUSE
--==================================================

UserInputService.InputChanged:Connect(function(input)

	if not rightMouseDown then
		return
	end

	if input.UserInputType ~= Enum.UserInputType.MouseMovement then
		return
	end

	local delta = input.Delta

	yaw -= delta.X * MOUSE_SENSITIVITY
	pitch -= delta.Y * MOUSE_SENSITIVITY

	-- Evitar que la cámara se voltee completamente
	pitch = math.clamp(
		pitch,
		math.rad(-89),
		math.rad(89)
	)
end)

--==================================================
-- CÁMARA
--==================================================

local function updateCamera(deltaTime)

	if not camera then
		return
	end

	-- Rotación de la cámara
	local rotation =
		CFrame.Angles(0, yaw, 0)
		* CFrame.Angles(pitch, 0, 0)

	local forward = rotation.LookVector
	local right = rotation.RightVector
	local up = Vector3.new(0, 1, 0)

	local movement = Vector3.zero

	--==================================================
	-- MOVIMIENTO DE FREECAM
	--==================================================

	-- I = adelante
	if keys.I then
		movement += forward
	end

	-- K = atrás
	if keys.K then
		movement -= forward
	end

	-- J = izquierda
	if keys.J then
		movement -= right
	end

	-- L = derecha
	if keys.L then
		movement += right
	end

	-- U = arriba
	if keys.U then
		movement += up
	end

	-- O = abajo
	if keys.O then
		movement -= up
	end

	-- Normalizar para que diagonal no sea más rápida
	if movement.Magnitude > 0 then
		movement = movement.Unit
	end

	-- Velocidad
	local speed = CAMERA_SPEED

	if keys.Shift then
		speed = FAST_CAMERA_SPEED
	end

	-- Mover cámara
	cameraPosition += movement * speed * deltaTime

	-- Aplicar posición y rotación
	camera.CFrame =
		CFrame.new(cameraPosition)
		* CFrame.Angles(0, yaw, 0)
		* CFrame.Angles(pitch, 0, 0)
end

--==================================================
-- MOVIMIENTO DEL PERSONAJE
--==================================================

local function updateCharacter()

	if not humanoid then
		return
	end

	if humanoid.Health <= 0 then
		return
	end

	local moveX = 0
	local moveZ = 0

	-- WASD SOLO PARA EL PERSONAJE

	if keys.W then
		moveZ -= 1
	end

	if keys.S then
		moveZ += 1
	end

	if keys.A then
		moveX -= 1
	end

	if keys.D then
		moveX += 1
	end

	local movement = Vector3.new(
		moveX,
		0,
		moveZ
	)

	if movement.Magnitude > 0 then
		movement = movement.Unit
	end

	-- Movimiento normal del personaje
	humanoid:Move(movement, true)
end

--==================================================
-- LOOP
--==================================================

RunService.RenderStepped:Connect(function(deltaTime)

	updateCamera(deltaTime)

	updateCharacter()

end)