use embedded_graphics::{
    geometry::{Point, Size},
    mono_font::{ascii::FONT_10X20, MonoTextStyle},
    pixelcolor::{Rgb565, RgbColor},
    primitives::{Primitive, PrimitiveStyleBuilder, Rectangle},
    text::renderer::TextRenderer,
    Drawable,
};
use embedded_text::{style::TextBoxStyleBuilder, TextBox};

use crate::{
    app::WIDTH,
    message::{MessageDirection, MessageGroup},
};

use super::{textbox::TextBox as MyTextBox, Element};

const MESSAGE_BOX_WIDTH: u32 = 200;
const MESSAGE_BOX_HEIGHT: u32 = 64;

pub struct Chat {
    message_group: MessageGroup,
    textbox: MyTextBox,
}

impl Chat {
    pub fn new() -> Self {
        Self {
            message_group: MessageGroup::default(),
            textbox: MyTextBox::new(1, 218, 31, 1),
        }
    }
}

impl Element for Chat {
    type KeyPushReturn = ();

    fn render<
        E,
        DT: embedded_graphics::prelude::DrawTarget<
            Color = embedded_graphics::pixelcolor::Rgb565,
            Error = E,
        >,
    >(
        &mut self,
        dt: &mut DT,
    ) -> Result<(), E> {
        let textbox_style = TextBoxStyleBuilder::new().build();
        let character_style = MonoTextStyle::new(&FONT_10X20, Rgb565::BLACK);
        let rect_style = PrimitiveStyleBuilder::new()
            .fill_color(Rgb565::WHITE)
            .build();

        let mut y = 28;
        for msg in self.message_group.iter() {
            let bounds = Rectangle::new(
                Point::new(4, y),
                Size::new(MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT),
            );

            let mut text_box =
                TextBox::with_textbox_style(msg.content, bounds, character_style, textbox_style);

            let mut actual_bounds = calculate_bounding_box(&text_box);
            if msg.direction == MessageDirection::To {
                let x = i32::try_from(WIDTH).unwrap()
                    - i32::try_from(actual_bounds.size.width).unwrap()
                    - 4;

                text_box.bounds.top_left.x = x;
                actual_bounds.top_left.x = x;
            }

            actual_bounds.into_styled(rect_style).draw(dt)?;

            text_box.draw(dt)?;

            y += i32::try_from(actual_bounds.size.height).unwrap() + 4;
        }

        self.textbox.render(dt)?;

        Ok(())
    }

    fn key_push(&mut self, k: crate::keyboard::KeyCode) {
        self.textbox.key_push(k);
    }
}

fn calculate_bounding_box<S: TextRenderer>(tb: &TextBox<'_, S>) -> Rectangle {
    const CHAR_WIDTH: u32 = 10;
    const CHAR_HEIGHT: u32 = 20;

    let mut x = 0;
    let mut max_x = 0;
    let mut y = 1;
    for c in tb.text.chars() {
        if c == '\n' || x >= CHAR_WIDTH * tb.bounds.size.width {
            x = 0;
            y += 1;
        } else {
            x += 1;
            max_x = x;
        }
    }

    Rectangle::new(
        tb.bounds.top_left,
        Size::new(max_x * CHAR_WIDTH, y * CHAR_HEIGHT),
    )
}