use bevy::prelude::*;

pub struct PathFollow2DPlugin;

impl Plugin for PathFollow2DPlugin {
	fn build(&self, app: &mut App) {}
}

#[derive(Component, Default)]
#[require(Transform)]
pub struct PathFollow2D {
	pub progress: f32,

	pub points: Vec<Vec2>,

	pub looping: bool,
}

impl PathFollow2D {
	pub fn length(&self) -> f32 {
		let mut len = 0f32;
		let no = self.points.len();
		for i in 0..no {
			if i < no - 1 {
				len += &self.points[i].distance(self.points[i + 1]);
			}
			else if self.looping && no > 2 {
				len += &self.points[i].distance(self.points[0]);
			}
		}
		len
	}

	pub fn get_progress_ratio(&self) -> f32 {
		self.progress / self.length()
	}

	pub fn set_progress(&mut self, progress: f32) {
		self.progress = self.progress.clamp(0.0, self.length());
	}

	pub fn get_pos(&self, dist: f32) -> (Vec2, Vec2) {
		let dist = dist.clamp(0.0, 1.0);
		let mut start_d = 0.0;

		let mut no = self.points.len();
		if self.looping {
			no += 1;
		}
		for i in 0..no {
			let end_d = (i + 1) as f32 / (no - 1) as f32;
			if dist < start_d || dist > end_d {
				start_d = end_d;
				continue;
			}

			let local_dist = (dist - start_d) / (end_d - start_d);

			let i1 = i;
			let mut i2 = 0;

			if i < no - 1 {
				i2 = i + 1;
			}
			if self.looping && i2 >= no - 1 {
				i2 = 0;
			}

			let v1 = &self.points[i1];
			let v2 = &self.points[i2];

			let d = v1.distance(*v2);

			let px = v1.x + (d * local_dist / d) * (v2.x - v1.x);
			let py = v1.y + (d * local_dist / d) * (v2.y - v1.y);
			let pos = Vec2::new(px, py);

			let dir = *v2 - *v1;
			let dir = dir.normalize();

			return (pos, dir);
		}
		(Vec2::default(), Vec2::default())
	}
}
