package doodle

// Subset of the PlayScene that is responsible for movement of the player character.

import (
	"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
	"git.kirsle.net/SketchyMaze/doodle/pkg/keybind"
	"git.kirsle.net/SketchyMaze/doodle/pkg/physics"
	"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
	"git.kirsle.net/go/render/event"
)

// movePlayer updates the player's X,Y coordinate based on key pressed.
func (s *PlayScene) movePlayer(ev *event.State) {
	var (
		playerSpeed = float64(balance.PlayerMaxVelocity)
		velocity    = s.Player.Velocity()
		direction   float64
		jumping     bool
		phys        = s.playerPhysics
		// holdingJump bool // holding down the jump button vs. tapping it
	)

	if s.slippery {
		phys = s.slipperyPhysics
	}

	// Antigravity: player can move anywhere with arrow keys.
	if s.antigravity || !s.Player.HasGravity() {
		velocity.X = 0
		velocity.Y = 0

		// Shift to slow your roll to 1 pixel per tick.
		if keybind.Shift(ev) {
			playerSpeed = 1
		}

		if keybind.Left(ev) {
			velocity.X = -playerSpeed
		} else if keybind.Right(ev) {
			velocity.X = playerSpeed
		}
		if keybind.Up(ev) {
			velocity.Y = -playerSpeed
		} else if keybind.Down(ev) {
			velocity.Y = playerSpeed
		}
	} else {
		// Moving left or right.
		if keybind.Left(ev) {
			direction = -1
		} else if keybind.Right(ev) {
			direction = 1
		}

		// Up button to signal they want to jump.
		if keybind.Up(ev) {
			if s.Player.IsWet() {
				// If they are holding Up put a cooldown in how fast they can swim
				// to the surface. Tapping the Jump button allows a faster ascent.
				if shmem.Tick > s.jumpCooldownUntil {
					s.jumpCooldownUntil = shmem.Tick + balance.SwimJumpCooldown
					velocity.Y = balance.SwimJumpVelocity
				}
			} else if s.Player.Grounded() || s.Player.IsCoyoteTime(true) {
				velocity.Y = balance.PlayerJumpVelocity
			}
		} else {
			s.jumpCooldownUntil = 0
			if velocity.Y < 0 {
				velocity.Y = 0
			}
		}

		// Moving left or right? Interpolate their velocity by acceleration.
		if direction != 0 {
			if s.playerLastDirection != direction {
				velocity.X = 0
			}

			// TODO: fast turn-around if they change directions so they don't
			// slip and slide while their velocity updates.
			velocity.X = physics.Lerp(
				velocity.X,
				direction*phys.MaxSpeed.X,
				phys.Acceleration,
			)
		} else {
			// Slow them back to zero using friction.
			velocity.X = physics.Lerp(
				velocity.X,
				0,
				phys.Friction,
			)
		}

		// Moving upwards (jumping): give them full acceleration upwards.
		if jumping {
			velocity.Y = -playerSpeed
		}

		// While in the air, count down their jump counter; when zero they
		// cannot jump again until they touch ground.
		if !s.Player.Grounded() {
			s.playerJumpCounter--
		}
	}

	s.playerLastDirection = direction

	// Move the player unless frozen.
	// TODO: if Y=0 then gravity fails, but not doing this allows the
	// player to jump while frozen. Not a HUGE deal right now as only Warp Doors
	// freeze the player currently but do address this later.
	if s.Player.IsFrozen() {
		velocity.X = 0
	}
	s.Player.SetVelocity(velocity)

	// If the "Use" key is pressed, set an actor flag on the player.
	s.Player.SetUsing(keybind.Use(ev))

	// Camera behaviors: Anvils can take the camera's focus while they're falling
	// but player inputs will take control back to the player. Most anvils will fall
	// a couple pixels upon level load - prevent them taking the camera's focus for
	// the first few frames of gameplay.
	if s.mustFollowPlayerUntil == 0 {
		s.mustFollowPlayerUntil = shmem.Tick + balance.FollowPlayerFirstTicks
	}

	// If we insist that the canvas follow the player doodad.
	// Also any directional key will focus the player unless the player is frozen.
	if shmem.Tick < s.mustFollowPlayerUntil || (!s.Player.IsFrozen() && (keybind.Up(ev) || keybind.Left(ev) || keybind.Right(ev) || keybind.Use(ev))) {
		s.drawing.FollowActor = s.Player.ID()
	}

	s.scripting.To(s.Player.ID()).Events.RunKeypress(keybind.FromEvent(ev))
}
