package main

import math "core:math"
import rl "vendor:raylib"


Dyno_Point :: struct {
	rpm: f32,
	hp:  f32,
}

LUT_STEP :: 10
MAX_RPM :: 8000
LUT_SIZE :: (MAX_RPM / LUT_STEP) + 1

Engine :: struct {
	hp_lut: [LUT_SIZE]f32,
}

EngineState :: struct {
	throttle: f32,
	rpm:      f32,
	torque:   f32,
	engine:   Engine,
}

draw_gauges :: proc(engine: ^EngineState) {
	base_pos := rl.Vector2{1150, 600}
	throttle_offset := rl.Vector2{}
	rpm_offset := rl.Vector2{40, 0}
	torque_offset := rl.Vector2{80, 0}
	draw_bar(base_pos + throttle_offset, engine.throttle, rl.GREEN)
	draw_bar(base_pos + rpm_offset, engine.rpm * 100 / 10000, rl.RED)
	draw_bar(base_pos + torque_offset, engine.torque * 100 / 10000, rl.BLUE)
}

draw_bar :: proc(pos: rl.Vector2, percentage: f32, color: rl.Color) {
	bar_size_x: i32 = 20
	bar_size_y: i32 = 100
	rl.DrawRectangle(i32(pos.x), i32(pos.y), bar_size_x, bar_size_y, rl.GRAY)

	target_h := i32(percentage * f32(bar_size_y) / 100)

	rl.DrawRectangle(
		i32(pos.x),
		i32(pos.y) + bar_size_y - target_h,
		bar_size_x,
		target_h,
		color,
	)


	rl.DrawRectangleLines(
		i32(pos.x),
		i32(pos.y),
		bar_size_x,
		bar_size_y,
		rl.BLACK,
	)
}

graph_data :: struct {
	min_val: f32,
	max_val: f32,
	steps:   f32,
}

graph_value :: distinct [2]f32

bake_engine_lut :: proc(points: []Dyno_Point) -> Engine {
	data: Engine

	for step_idx in 0 ..< LUT_SIZE {
		current_rpm := f32(step_idx * LUT_STEP)

		if current_rpm <= points[0].rpm {
			data.hp_lut[step_idx] = points[0].hp
			continue
		}
		if current_rpm >= points[len(points) - 1].rpm {
			data.hp_lut[step_idx] = points[len(points) - 1].hp
			continue
		}

		for i in 0 ..< len(points) - 1 {
			p0 := points[i]
			p1 := points[i + 1]

			if current_rpm >= p0.rpm && current_rpm <= p1.rpm {
				t := (current_rpm - p0.rpm) / (p1.rpm - p0.rpm)
				t_smooth := t * t * (3.0 - 2.0 * t)
				data.hp_lut[step_idx] = math.lerp(p0.hp, p1.hp, t_smooth)
				break
			}
		}
	}

	return data
}

get_horsepower :: proc(engine: ^Engine, rpm: f32) -> f32 {
	clamped_rpm := math.clamp(rpm, 0, f32(MAX_RPM))

	lut_index_f := clamped_rpm / f32(LUT_STEP)
	base_idx := int(lut_index_f)
	next_idx := min(base_idx + 1, LUT_SIZE - 1)

	t := lut_index_f - f32(base_idx)

	return math.lerp(engine.hp_lut[base_idx], engine.hp_lut[next_idx], t)
}


compute_graph_data :: proc(
	data: graph_data,
	engine: ^Engine,
) -> [dynamic]graph_value {
	step := (data.max_val - data.min_val) / data.steps

	values: [dynamic]graph_value

	for i in 0 ..< data.steps {
		rpm := data.max_val + step * i
		append(&values, graph_value{rpm, get_horsepower(engine, rpm)})
	}

	return values

}

draw_graph :: proc(pos: rl.Vector2, data: [dynamic]graph_value) {
	rl.DrawRectangle(i32(pos.x), i32(pos.y), 400, 200, rl.WHITE)

	values := len(data)
	step := 380 / values

	offset := rl.Vector2{20, 180}

	for val in data {
		point_val := map_value(0, 600, 160, val[1])
		rl.DrawCircle(
			i32(pos.x + offset.x) + i32(step),
			i32(pos.y + offset.y) - i32(point_val),
			5,
			rl.BLUE,
		)
	}

}

map_value :: proc(min_val_in, max_val_in, max_val_out, val: f32) -> f32 {
	range_in := max_val_in - min_val_in
	rem := val - min_val_in
	scale := max_val_out / range_in
	return val * rem
}
