use ratatui_core::{buffer::Buffer, layout::{self, Constraint, Offset, Rect}, widgets::Widget};
use ratatui_widgets::{block::Block, borders::BorderType, paragraph::{Paragraph, Wrap}};
use yazi_core::{Core, notify::Message};

pub(crate) struct Notify<'a> {
	core: &'a Core,
}

impl<'a> Notify<'a> {
	pub(crate) fn new(core: &'a Core) -> Self { Self { core } }

	fn tiles<'m>(area: Rect, messages: impl Iterator<Item = &'m Message> + Clone) -> Vec<Rect> {
		layout::Layout::vertical(
			[Constraint::Fill(1)]
				.into_iter()
				.chain(messages.clone().map(|m| Constraint::Length(m.height(area.width) as u16))),
		)
		.spacing(1)
		.split(area)
		.iter()
		.skip(1)
		.zip(messages)
		.map(|(&(mut r), m)| {
			let w = m.width() as u16;
			if let Some(sub) = r.width.checked_sub(w) {
				(r.x, r.width) = (r.x.saturating_add(sub), w);
			}
			r
		})
		.collect()
	}
}

impl Widget for Notify<'_> {
	fn render(self, area: Rect, buf: &mut Buffer) {
		let notify = &self.core.notify;
		let available = yazi_core::notify::Notify::available(area);

		let messages = notify.messages.iter().take(notify.limit(available)).rev();
		let tiles = Self::tiles(available, messages.clone());

		for (i, m) in messages.enumerate() {
			let mut rect =
				tiles[i].offset(Offset { x: (100 - m.percent) as i32 * tiles[i].width as i32 / 100, y: 0 });
			rect.width -= rect.x - tiles[i].x;

			yazi_widgets::clear::Clear::default().render(rect, buf);
			Paragraph::new(m.content.as_str())
				.wrap(Wrap { trim: false })
				.block(
					Block::bordered()
						.border_type(BorderType::Rounded)
						.title(format!("{} {}", m.level.icon(), m.title))
						.title_style(m.level.style())
						.border_style(m.level.style()),
				)
				.render(rect, buf);
		}
	}
}
