// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use egui::{Context, Frame, Window, Button, Margin, Stroke, Rounding, Align2, Color32};

use super::hud::text_io::{YELLOW, RED};

use crate::app::gui::{style::{LABEL_SIZE, LABEL_COLOUR}, layout_job_helper::LayoutJobHelper};
use crate::protocol::message::{StoryText, StoryTextColour};

const BACKGROUND: u8 = 0x0f;
const BORDER: u8 = 0x7f;

#[derive(Default)]
pub struct StoryTextInfo {
	text: Vec<StoryText>,
	index: usize,
	just_changed: bool,
}

impl StoryTextInfo {
	pub fn empty() -> StoryTextInfo {
		StoryTextInfo::new(Vec::new())
	}

	pub fn new(text: Vec<StoryText>) -> StoryTextInfo {
		StoryTextInfo {
			text,
			index: 0,
			just_changed: true,
		}
	}

	pub fn open(&self) -> bool {
		self.index < self.text.len()
	}

	pub fn next(&mut self) {
		self.index += 1;
		self.just_changed = true;
	}

	pub fn render(&mut self, ctx: &Context) {
		let Some(story_text) = self.text.get(self.index) else { return; };

		let frame = Frame::none()
			.fill(Color32::from_rgba_unmultiplied(BACKGROUND, BACKGROUND, BACKGROUND, 0xcf))
			.stroke(Stroke::new(1.0, Color32::from_gray(BORDER)))
			.rounding(Rounding::same(4.0))
			.inner_margin(Margin::same(16.0));

		let lwinsize = ctx.screen_rect().size();
		let window_size = lwinsize / 2.0;
		let mut next = false;

		Window::new("story")
			.frame(frame)
			.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
			.resizable(false)
			.title_bar(false)
			.scroll([false, true])
			.fixed_size(window_size)
			.show(ctx, |ui| {
				let mut job = LayoutJobHelper::new(LABEL_SIZE);
				for (text, colour) in story_text {
					let colour = match colour {
						StoryTextColour::Normal => LABEL_COLOUR,
						StoryTextColour::Yellow => YELLOW,
						StoryTextColour::Red => RED,
					};
					job = job.add(text, colour);
				}

				if self.just_changed {
					/*
					 * Scrolls to the top of the window whenever changing the opened
					 * story text.
					 *
					 * This isn't a perfect solution as a scrolling animation is
					 * shown. Calling `scroll_to_cursor_animation` with the animation
					 * disabled doesn't fix this because there is still a short
					 * period of time it takes to scroll back, and looks worse
					 * because it's less smooth.
					 */
					ui.scroll_to_cursor(None);
					self.just_changed = false;
				}

				ui.style_mut().interaction.selectable_labels = true;
				ui.label(job.build());

				let space_needed = (window_size.y - ui.min_size().y - 32.0 - LABEL_SIZE).max(LABEL_SIZE);
				ui.add_space(space_needed);
				ui.vertical_centered(|ui| {
					let button = Button::new(if self.index + 1 < self.text.len() { "Next" } else { "Close" }).fill(Color32::from_gray(0x1f)).stroke(Stroke::new(1.0, Color32::from_gray(BORDER)));
					if ui.add(button).clicked() {
						next = true;
					}
				});
			});

		if next {
			self.next();
		}
	}
}
