// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use std::{fs, path::Path};

use glium::{Surface, VertexBuffer, Display, Program, Frame, DrawParameters, index::{NoIndices, PrimitiveType}, uniform, implement_vertex};
use glutin::surface::WindowSurface;
use glam::Mat4;

use crate::app::filesystem::{Filesystem, FsBase};
use crate::world::special_area::SpecialArea;
use crate::utils::glium_resize;

#[derive(Clone, Copy)]
struct Vertex { v_pos: [f32; 2], v_colour: [f32; 4] }
implement_vertex!(Vertex, v_pos, v_colour);

pub struct SpecialAreaRenderer {
	vbo: VertexBuffer<Vertex>,
	program: Program,
	count: usize,
}

impl SpecialAreaRenderer {
	pub fn new(display: &Display<WindowSurface>, fs: &Filesystem) -> SpecialAreaRenderer {
		let vsh = fs::read_to_string(fs.get(FsBase::Static, Path::new("shaders/special_area.vsh"))).unwrap();
		let fsh = fs::read_to_string(fs.get(FsBase::Static, Path::new("shaders/special_area.fsh"))).unwrap();

		SpecialAreaRenderer {
			vbo: VertexBuffer::empty_persistent(display, 0).unwrap(),
			program: Program::from_source(display, &vsh, &fsh, None).unwrap(),
			count: 0,
		}
	}

	pub fn reset(&mut self, areas: &[SpecialArea], display: &Display<WindowSurface>) {
		self.count = areas.len() * 3;
		glium_resize::vbo_persistent(&mut self.vbo, display, self.count);

		{
			let mut buf = self.vbo.map_write();
			let mut i = 0;
			for area in areas {
				let (p0, p1, p2) = area.get_points();
				let colour = area.get_colour();
				buf.set(i    , Vertex { v_pos: p0.to_array(), v_colour: colour.into() });
				buf.set(i + 1, Vertex { v_pos: p1.to_array(), v_colour: colour.into() });
				buf.set(i + 2, Vertex { v_pos: p2.to_array(), v_colour: colour.into() });
				i += 3;
			}
		}
	}

	pub fn render(&self, frame: &mut Frame, params: &DrawParameters, proj_matrix: &Mat4) {
		let uniforms = uniform! { u_matrix: proj_matrix.to_cols_array_2d() };
		frame.draw(self.vbo.slice(..self.count).unwrap(), NoIndices(PrimitiveType::TrianglesList), &self.program, &uniforms, params).unwrap();
	}
}
