// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
mod state;
pub mod style;
pub mod title;
pub mod play_selection;
pub mod settings;
pub mod about;
pub mod layout_job_helper;
mod port_edit;

pub use state::GuiState;

use std::{fs, path::Path, sync::Arc};

use egui::{ViewportId, FontDefinitions, FontFamily, FontData, FontId, TextStyle, Context};
use egui_glium::{EguiGlium, EventResponse};
use glium::{Display, Frame as GliumFrame};
use glutin::surface::WindowSurface;
use winit::{window::Window, event::{WindowEvent, MouseScrollDelta}, event_loop::EventLoop, dpi::PhysicalPosition};

use style::LABEL_SIZE;

use crate::app::{filesystem::{Filesystem, FsBase}, config::Config};

pub struct Gui {
	inner: EguiGlium,
	extra_pass: bool,
}

impl Gui {
	pub fn new(display: &Display<WindowSurface>, window: &Window, fs: &Filesystem, event_loop: &EventLoop<()>, config: &Config) -> Gui {
		let inner = EguiGlium::new(ViewportId::ROOT, display, window, event_loop);
		let ctx = inner.egui_ctx();
		ctx.set_zoom_factor(config.accessibility.scale_factor);
		let mut fonts = FontDefinitions::empty();
		fonts.font_data.insert(String::from("normal"), FontData::from_owned(fs::read(fs.get(FsBase::Static, Path::new("fonts/inter.otf"))).unwrap()));
		fonts.font_data.insert(String::from("scores"), FontData::from_owned(fs::read(fs.get(FsBase::Static, Path::new("fonts/press_start_2p.ttf"))).unwrap()));

		let scores = Arc::from("scores");
		fonts.families.insert(FontFamily::Proportional, vec![String::from("normal")]);
		fonts.families.insert(FontFamily::Name(Arc::clone(&scores)), vec![String::from("scores")]);

		ctx.options_mut(|options| {
			options.line_scroll_speed = 120.0;
			options.zoom_with_keyboard = false; // Don't want to worry about this being inconsistent with the scaling in the accessibility config and having to sync them
		});

		ctx.set_fonts(fonts);
		ctx.style_mut(|style| {
			style.text_styles = [
				(TextStyle::Heading, FontId::proportional(16.0)),
				(TextStyle::Body, FontId::proportional(LABEL_SIZE)),
				(TextStyle::Button, FontId::proportional(16.0)),
			].into();

			style::set(style);
		});

		Gui { inner, extra_pass: false }
	}

	pub fn window_event(&mut self, window: &Window, event: &WindowEvent) -> EventResponse {
		if let WindowEvent::MouseWheel { device_id, delta: MouseScrollDelta::PixelDelta(PhysicalPosition { x, y }), phase } = *event {
			// Hacky fix to https://github.com/emilk/egui/issues/5342 to increase the touchpad scrolling speed on Wayland
			self.inner.on_event(window, &WindowEvent::MouseWheel { device_id, delta: MouseScrollDelta::PixelDelta(PhysicalPosition { x: x * 10.0, y: y * 10.0 }), phase })
		} else {
			self.inner.on_event(window, event)
		}
	}

	pub fn update(&mut self, window: &Window, mut add_contents: impl FnMut(&Context)) {
		if self.extra_pass { // Avoids first-frame jitters
			self.extra_pass = false;
			self.inner.egui_ctx().request_discard("");
		}

		self.inner.run(window, &mut add_contents);
	}

	pub fn zoom_factor(&self) -> f32 {
		self.inner.egui_ctx().zoom_factor()
	}

	pub fn do_extra_pass(&mut self) {
		self.extra_pass = true;
	}

	pub fn render(&mut self, display: &Display<WindowSurface>, frame: &mut GliumFrame) {
		self.inner.paint(display, frame);
	}
}
