package main

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

// Virtual game field dimensions
GameField := vec2{400, 200}

Game :: struct {
	using state: GameState,
	health: u8,
	player: Player,
	camera: rl.Camera3D,
	camera_offset: vec3,
	score: u32,
	background: rl.Texture,
	plane: rl.Model,
	bullets: [dynamic]Bullet,
	snake_max_health: int,
	snake_health: int,
	music: rl.Music,
	tutorial_enabled: bool,
	tutorial_finished: bool,
	tutorial_timer: f32,
	tutorial_step: TutorSteps
}

TutorSteps :: enum {
	THRUST,
	LOOK,
	SHOOT,
	DODGE,
	DONE
}

TutorTextsMouse := [TutorSteps]cstring{
	.THRUST = "Используйте W/Ц для ускорения",
	.LOOK = "Двигайте мышью для наведения",
	.SHOOT = "Левая кнопка мыши: стрельба",
	.DODGE = "Правая кнопка мыши: уклонение",
	.DONE = "Удачи!"
}

TutorTextsKeyboard := [TutorSteps]cstring{
	.THRUST = "Используйте стрелку \"Вверх\" для ускорения",
	.LOOK = "Стрелки \"Влево\"/\"Вправо\" для наведения",
	.SHOOT = "Пробел: стрельба",
	.DODGE = "Shift: уклонение",
	.DONE = "Удачи!"
}

game_init :: proc(prev: ^GameState = nil) -> ^GameState {
	state := new(Game)
	state.previous = prev
	state.variant = state
	state.draw = game_draw
	state.update = game_update
	state.free = game_free
	rlgl.DisableBackfaceCulling()

	img := rl.GenImageChecked(1024, 1024, 128, 128, rl.Color{60, 255, 255, 255}, rl.Color{30, 220, 220, 255})
	state.background = rl.LoadTextureFromImage(img)
	
	state.plane = rl.LoadModel(".\\assets\\models\\background.obj")
	rl.UnloadImage(img)

	game_setup(state)
	return state
}

game_setup :: proc(game: ^Game) {
	clear(&game.bullets)
	clear(&Segments)
	clear(&trails)
	clear(&explosions)
	explosions_init()
	trail_init()
	game.player = player_spawn({GameField.x / 2 + 70, 20, 0})
	// rl.StopMusicStream(game.music)

	game.health = 100
	game.snake_max_health = 0

	snake_spawn({0, -10, 0}, math.PI * 3 / 2, 100)
	for segment in Segments {
		game.snake_max_health += int(segment.health)
	}

	game.camera = rl.Camera3D{
		target = game.player.pos, 
		position = game.player.pos + vec3backward * 50,
		fovy = 60,
		//offset = WSize/2,
		projection = rl.CameraProjection.PERSPECTIVE,
		up = vec3up
	}
	game.camera.target.x = clamp(game.camera.target.x, -GameField.x/2, GameField.x/2)
	game.camera.target.y = clamp(game.camera.target.y, 0, GameField.y)
	game.camera.position = game.camera.target + vec3backward * 50

	game.tutorial_timer = 3
}


game_gen_level :: proc(game: ^Game) {

}

game_update :: proc(state: ^GameState, delta: f32) {
	game := transmute(^Game)state
	using game
	tutorial_enabled = NeedTutorial && !tutorial_finished && player.intro_timer <= 0
	if tutorial_enabled {
		tutorial_timer -= delta
		if tutorial_timer <= 0 {
			tutorial_timer = 3
			switch tutorial_step {
				case .THRUST: tutorial_step = .LOOK
				case .LOOK: tutorial_step = .SHOOT
				case .SHOOT: tutorial_step = .DODGE
				case .DODGE: tutorial_step = .DONE; tutorial_timer = 2
				case .DONE: 
					tutorial_finished = true
					NeedTutorial = false
					SnakeActive = true
					rl.PlaySound(Res.Sfx.SnakeRoarBlast)
			}
		}
	} else {
		if player.intro_timer <= 0 && !SnakeActive {
			SnakeActive = true
		}
	}


	// if rl.IsMusicStreamPlaying(game.music) {
		rl.UpdateMusicStream(game.music)
	// }
	explosions_process(delta)

	if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
		pause := pause_init(game)
		stack_push(pause)
	}
	

	player_update(&player, game, delta)
	#reverse for &bullet, i in bullets {
		bullet_process(&bullet, game, delta)
		if !bullet.alive {
			unordered_remove(&bullets, i)
		}
	}
	snake_process(game, delta)
	target_offset := player.vel / 5
	camera_offset = rl.Vector3MoveTowards(camera_offset, target_offset, rl.Vector3Length(target_offset - camera_offset) * 10 * delta)
	camera.target = player.pos + camera_offset
	camera.target.x = clamp(camera.target.x, -GameField.x/2, GameField.x/2)
	camera.target.y = clamp(camera.target.y, 0, GameField.y)
	camera.position = camera.target + vec3backward * 50
	trail_update(delta)
}

game_draw :: proc(state: ^GameState) {
	rlgl.SetLineWidth(4)
	game := transmute(^Game)state
	using game 

	rl.BeginMode3D(camera)
	rl.DrawModel(game.plane, {0, 0, 500}, 1000, rl.WHITE)

	yy : i32 = 0

	snake_draw(game)
	player_draw(&player)

	for &bullet, i in bullets {
		bullet_draw(&bullet, game)
		if i != 0 {
			// rl.DrawLine3D(bullets[i].pos, bullets[i-1].pos, rl.WHITE)
		}
	}
	trail_draw()
	explosions_draw()
	rl.EndMode3D()


	if stack_top() == game {
		hb_text : cstring = "Jörmungandr"
		height := 30 * (WSize.y / 480)
		hb_health : f32 = f32(snake_health) / f32(snake_max_health)
		if snake_health == 0 {
			hb_health = f32(Head.health) / f32(Head.max_health)
			hb_text = "Jörmungandr's head"
		}
		// rl.DrawRectangleV({0, WSize.y - height - 10}, {WSize.x, height + 10}, rl.WHITE)
		// hb_width := hb_health * WSize.x
		// rl.DrawRectangleV({WSize.x / 2 - hb_width / 2, WSize.y - height - 7}, {hb_width, height + 4}, rl.RED)
		// draw_text_centered(Res.Fonts.Title, hb_text, {WSize.x / 2, WSize.y - height / 2}, height)
		if SnakeActive {
			draw_hbar(hb_text, hb_health, {0, WSize.y - height}, {WSize.x, height}, rl.RED)
		}
		draw_hbar("Þórr", f32(health) / 100.0, {0, 0}, {WSize.x, height}, rl.GREEN)
		reload_color := rl.SKYBLUE
		if player.reloading {
			reload_color = rl.RED
		}
		draw_hbar("", f32(player.power) / 100.0, {0, height}, {WSize.x, 10}, reload_color)

		if tutorial_enabled {
			texts := TutorTextsMouse
			if KeyboardOnly {
				texts = TutorTextsKeyboard
			}
			draw_text_centered(Res.Fonts.UI, texts[tutorial_step], WSize / 2 + vec2{0, 100}, 48, 1, rl.WHITE)
		}

	}
}

draw_hbar :: proc(text: cstring, value: f32, pos, size: vec2, color: rl.Color) {
	rl.DrawRectangleV(pos, size, rl.WHITE)
	hb_width := value * size.x
	rl.DrawRectangleV(pos + {size.x / 2 - hb_width / 2, 2}, {hb_width, size.y - 4}, color)
	draw_text_centered(Res.Fonts.Title, text, pos + size / 2, size.y / 1.3)
}



game_free :: proc(state: ^GameState) {
	game := transmute(^Game)state 
	rl.UnloadTexture(game.background)
	free(state)
}


