// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use glam::Vec2;

use super::edge::Edge;

pub struct Line { a: f32, b: f32, c: f32 }

impl Line {
	/**
	 * Converts from (x₀, y₀), θ where (x₀, y₀) is a point on the line and θ is
	 * the angle, to ax + by + c = 0.
	 */
	pub fn new(x0: f32, y0: f32, angle: f32) -> Line {
		let (sin, cos) = angle.sin_cos();
		Line {
			a: sin,
			b: -cos,
			c: -x0 * sin + y0 * cos,
		}
	}

	/**
	 * Checks whether this line is intersecting (and not parallel) with the
	 * provided edge. Returns the point of collision if intersecting, otherwise
	 * None.
	 */
	pub fn intersecting(&self, edge: &Edge) -> Result<Option<Vec2>, ()> {
		// t ∈ (0, 1) if on the line
		// Returns ±∞ or NaN if parallel, getting division by zero
		let t = (self.a * edge.0.x + self.b * edge.0.y + self.c) / (self.a * (edge.0.x - edge.1.x) + self.b * (edge.0.y - edge.1.y));
		if t > 0.0 && t < 1.0 {
			Ok(Some(edge.0.lerp(edge.1, t)))
		} else if t == 0.0 || t == 1.0 { // If colliding with the endpoints (very rare), error as I don't want to handle that case
			Err(())
		} else {
			Ok(None)
		}
	}
}
