package main

import "core:fmt"
import "core:math"
import "core:math/ease"
import "core:math/rand"
import "core:slice"
import "core:strings"
import "ntween"
import rl "vendor:raylib"
import "vendor:raylib/rlgl"


// PlayerAnims : [^]rl.ModelAnimation
// PlayerAnimsCount : i32

Player :: struct {
	pos:             vec3,
	vel:             vec3,
	dir:             f32,
	radius:          f32,
	thrust:          f32,
	max_speed:       f32,
	rolling:         f32,
	charge:          f32,
	is_dodging:      bool,
	can_dodge:       bool,
	can_shoot:       bool,
	is_invulnerable: bool,
	is_dead:         bool,
	intro_timer:     f32,
	power:           f32,
	reload_timer:    f32,
	reloading:       bool,
	// animation: rl.ModelAnimation,
	// animTime: f32,
	// animFrame: i32,
}


player_spawn :: proc(position: vec3) -> Player {

	// PlayerAnims = rl.LoadModelAnimations(PlayerModelPath, &PlayerAnimsCount)
	return Player {
		pos = position,
		radius = 1,
		max_speed = 40,
		dir = 0,
		vel = {-80, 0, 0},
		can_dodge = true,
		can_shoot = true,
		intro_timer = 2,
		power = 100,
	}
}

player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
	using player

	if intro_timer > 0 {
		intro_timer -= delta
	}


	mouse_ray := rl.GetMouseRay(rl.GetMousePosition(), game.camera)
	mouse_pos: vec3
	hit := rl.GetRayCollisionQuad(
		mouse_ray,
		{-1000, -1000, 0},
		{-1000, 1000, 0},
		{1000, 1000, 0},
		{1000, -1000, 0},
	)
	if hit.hit {
		mouse_pos = hit.point
	}

	mouse_diff := mouse_pos - pos
	mouse_angle := math.atan2(-mouse_diff.y, mouse_diff.x)

	if !is_dead {
		pos += vel * delta
		if pos.y < radius {
			pos.y = radius
			vel.y = -vel.y
		}
		if !is_dodging {
			dir_vector: vec3
			if intro_timer <= 0 {
				thrust_key := rl.KeyboardKey.W
				if !KeyboardOnly {
					dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
					dir_vector = get_vec_from_angle(dir)
				} else {
					thrust_key = rl.KeyboardKey.UP
					if rl.IsKeyDown(rl.KeyboardKey.LEFT) {
						dir += math.PI * 2 * delta
					}
					if rl.IsKeyDown(rl.KeyboardKey.RIGHT) {
						dir -= math.PI * 2 * delta
					}
					dir_vector = get_vec_from_angle(dir)
				}
				thrust = 0
				if rl.IsKeyDown(thrust_key) {
					thrust = 110
				}
			} else {
				thrust = 110
				dir_vector = vec3left
				dir = math.atan2(-dir_vector.y, dir_vector.x)
			}
			if thrust > 0 {
				roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
				vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
				offset := rl.Vector3RotateByAxisAngle(vec3backward, vec3right, roll) * 2.6
				offset = rl.Vector3RotateByAxisAngle(offset, vec3backward, dir)
				pl := pos + offset
				pr := pos - offset
				trail(pl, 1, rand.float32_range(1.7, 3.5))
				trail(pr, 1, rand.float32_range(1.7, 3.5))
			}
		}
		if thrust == 0 {
			vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
			rl.StopSound(Res.Sfx.Rocket)
		} else {
			if !rl.IsSoundPlaying(Res.Sfx.Rocket) && !is_dodging {
				rl.PlaySound(Res.Sfx.Rocket)
			}
		}

		dodge := false
		shoot := false
		if KeyboardOnly {
			dodge = rl.IsKeyPressed(rl.KeyboardKey.LEFT_SHIFT)
			shoot = rl.IsKeyDown(rl.KeyboardKey.SPACE)
		} else {
			dodge = rl.IsMouseButtonPressed(rl.MouseButton.RIGHT)
			shoot = rl.IsMouseButtonDown(rl.MouseButton.LEFT)
		}

		if dodge && can_dodge && intro_timer <= 0 {
			is_dodging = true
			can_dodge = false
			rl.StopSound(Res.Sfx.Rocket)
			rl.PlaySound(Res.Sfx.PlayerSwoosh)
			ntween.animate(
				&f32_tweens,
				&player.rolling,
				math.PI * 2,
				0.42,
				ease.Ease.Quadratic_Out,
			)
			timer_start(0.45, player, proc(data: rawptr) {
				player := transmute(^Player)data
				player.is_dodging = false
				player.rolling = 0
			})
			timer_start(0.55, player, proc(data: rawptr) {
				player := transmute(^Player)data
				player.can_dodge = true
			})
		}

		// player.animation = PlayerAnims[1]
		// player.animTime += delta
		// player.animFrame = i32(player.animTime * 60) % player.animation.frameCount
		// rl.UpdateModelAnimation(PlayerModel, player.animation, player.animFrame)
		shooting := shoot && !is_dodging && intro_timer <= 0 && !reloading
		if shooting {
			if !rl.IsSoundPlaying(Res.Sfx.Lightning) {
				rl.PlaySound(Res.Sfx.Lightning)
			}
			if can_shoot {
				roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
				b := bullet_spawn(
					pos + get_vec_from_angle(dir) * 3 + get_vec_from_angle(dir + math.PI / 2) * .3,
					dir,
				)
				append(&game.bullets, b)
				can_shoot = false
				timer_start(0.07, player, proc(data: rawptr) {
					player := transmute(^Player)data
					player.can_shoot = true
				})
				player.power -= 2
				player.reload_timer = 1
				if player.power <= 0 {
					player.reloading = true
					player.power = 0
				}
			}
		} else {
			rl.StopSound(Res.Sfx.Lightning)
		}
		if !shooting && can_shoot {
			reload_timer -= delta
			if reload_timer <= 0 {
				player.power += 20 * delta
				if player.power > 100 {
					player.power = 100
					player.reloading = false
				}
			}
		}
	}

	got_hit := false

	hit: if !is_invulnerable && !is_dodging && !is_dead {
		if rl.CheckCollisionCircles(pos.xy, radius, Head.pos.xy, Head.radius) {
			got_hit = true
			break hit
		}
		ray := rl.Ray {
			position  = Head.pos,
			direction = get_vec_from_angle(Head.dir),
		}
		if Head.is_shooting && rl.GetRayCollisionSphere(ray, pos, radius + 3).hit {
			got_hit = true
			break hit
		}
		for segment in Segments {
			if rl.CheckCollisionCircles(pos.xy, radius, segment.pos.xy, radius) {
				got_hit = true
				break
			}
		}
	}
	if rl.IsKeyPressed(rl.KeyboardKey.M) {
		got_hit = true
	}

	if got_hit {
		game.health -= 10
		rl.PlaySound(Res.Sfx.PlayerHit)
		is_invulnerable = true
		timer_start(1, player, proc(data: rawptr) {
			plr := transmute(^Player)data
			plr.is_invulnerable = false
		})
		if game.health <= 0 && !is_dead {
			is_dead = true
			explode(pos, 10, 0.8, rl.WHITE)
			rl.StopMusicStream(current_music)
			rl.PlaySound(Res.Sfx.PlayerDead)
			timer_start(3, game, proc(data: rawptr) {
				state := transmute(^Game)data
				screen := gameover_init(state)
				stack_push(screen)
			})
		}
	}

}


player_draw :: proc(player: ^Player) {
	using player
	if player.is_dead {return}
	dir_vector := get_vec_from_angle(dir)
	color := rl.WHITE
	if is_invulnerable {
		color = rl.Color{255, 170, 170, 255}
	}

	roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
	rlgl.PushMatrix()
	rlgl.Translatef(pos.x, pos.y, pos.z)
	rlgl.Rotatef(math.to_degrees(dir), 0, 0, -1)
	rlgl.Rotatef(math.to_degrees(roll + player.rolling), 1, 0, 0)
	// rl.DrawCircle3D({}, radius, vec3up, 0, color)
	// rl.DrawLine3D({}, {-4, 0, 0}, rl.GREEN)
	rl.DrawModel(Res.Models.PlayerModel, {}, 6, color)
	rlgl.PopMatrix()
	// rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
	// rl.DrawLine3D(pos, pos + vel, rl.RED)

}
