use embedded_graphics::{
    geometry::{Point, Size},
    pixelcolor::Gray8,
    prelude::{DrawTarget, OriginDimensions},
    primitives::Rectangle,
};

use crate::ui::{
    generated_fonts,
    typography::{TextRenderer, TextStyle},
};

pub(crate) struct Frame<'a, D>
where
    D: DrawTarget<Color = Gray8> + OriginDimensions,
{
    target: &'a mut D,
}

impl<'a, D> Frame<'a, D>
where
    D: DrawTarget<Color = Gray8> + OriginDimensions,
{
    pub fn new(target: &'a mut D) -> Self {
        Self { target }
    }

    pub fn clear(&mut self) -> Result<(), D::Error> {
        self.target.clear(Gray8::new(255))
    }

    pub fn title(&mut self, text: &str) -> Result<(), D::Error> {
        self.text(text, Point::new(40, 18), Self::title_style())
    }

    pub fn body(&mut self, y: i32, text: &str) -> Result<(), D::Error> {
        self.text(text, Point::new(48, y), Self::body_style())
    }

    pub fn small(&mut self, y: i32, text: &str) -> Result<(), D::Error> {
        self.text(text, Point::new(48, y), Self::small_style())
    }

    pub fn footer(&mut self, text: &str) -> Result<(), D::Error> {
        let size = self.target.size();
        let body_style = Self::body_style();
        let small_style = Self::small_style();
        let max_width = size.width as i32 - 64;

        if body_style.measure_width(text) <= max_width {
            let y = size.height as i32 - i32::from(body_style.line_height()) - 6;
            return self.text(text, Point::new(32, y), body_style);
        }

        let y = if small_style.measure_width(text) <= max_width {
            size.height as i32 - i32::from(small_style.line_height()) - 6
        } else {
            size.height as i32 - i32::from(small_style.line_height()) * 2 - 6
        };
        let bounds = Rectangle::new(
            Point::new(32, y),
            Size::new(max_width as u32, u32::from(small_style.line_height()) * 2),
        );
        self.wrapped_text(text, bounds, small_style)
    }

    pub fn paragraph(&mut self, y: i32, text: &str) -> Result<(), D::Error> {
        let size = self.target.size();
        let x = 72;
        let bottom_margin = 88;
        let width = size.width.saturating_sub((x * 2) as u32);
        let height = size.height.saturating_sub(y as u32 + bottom_margin);
        let bounds = Rectangle::new(Point::new(x, y), Size::new(width, height));

        self.wrapped_text(text, bounds, Self::reader_style())
    }

    fn text(&mut self, text: &str, position: Point, style: TextStyle) -> Result<(), D::Error> {
        TextRenderer::new(self.target).draw_text(text, position, style)
    }

    fn wrapped_text(
        &mut self,
        text: &str,
        bounds: Rectangle,
        style: TextStyle,
    ) -> Result<(), D::Error> {
        TextRenderer::new(self.target).draw_wrapped_text(text, bounds, style)
    }

    fn title_style() -> TextStyle {
        TextStyle::new(&generated_fonts::QUATTRO_TITLE, Gray8::new(0), 46)
    }

    fn body_style() -> TextStyle {
        TextStyle::new(&generated_fonts::QUATTRO_BODY, Gray8::new(0), 38)
    }

    fn reader_style() -> TextStyle {
        TextStyle::new(&generated_fonts::QUATTRO_READER, Gray8::new(0), 43)
    }

    fn small_style() -> TextStyle {
        TextStyle::new(&generated_fonts::QUATTRO_SMALL, Gray8::new(0), 30)
    }
}
