Documentation
use crate::{Content, Element, Handle, Hatmel};
use std::ops::Deref;
use termit::prelude::*;

#[derive(Default)]
pub struct W3t<A: AppEvent> {
    ui: UiNode<A>,
}

impl<A: AppEvent> Widget<Hatmel, A> for W3t<A> {
    fn update(
        &mut self,
        model: &mut Hatmel,
        input: &termit::prelude::Event<A>,
        screen: &mut termit::Screen,
        painter: &termit::Painter,
    ) -> termit::prelude::Window {
        self.ui.handle = Some(0);
        self.ui.update(model, input, screen, painter)
    }
}

pub struct UiNode<A: AppEvent> {
    handle: Option<Handle>,
    revision: usize,
    ui: Box<dyn Widget<Hatmel, A> + 'static>,
}
impl<A: AppEvent> Default for UiNode<A> {
    fn default() -> Self {
        Self {
            handle: None,
            revision: usize::MAX,
            ui: Box::new(()),
        }
    }
}
impl<A: AppEvent> UiNode<A> {
    pub fn new(handle: Handle) -> Self {
        Self {
            handle: Some(handle),
            revision: usize::MAX,
            ui: Box::new(()),
        }
    }
}

impl<A: AppEvent> Widget<Hatmel, A> for UiNode<A> {
    fn update(
        &mut self,
        model: &mut Hatmel,
        input: &Event<A>,
        screen: &mut Screen,
        painter: &Painter,
    ) -> Window {
        if model.revision() != self.revision {
            let (handle, content) = match self
                .handle
                .and_then(|handle| model.get(handle).map(|content| (handle, content)))
            {
                None => {
                    *self = Self::default();
                    return painter.scope().trim(point(0, 0));
                }
                Some(some) => some,
            };

            let mut dent = 4;
            let mut stack = Stack::south_east(vec![]);

            match content {
                Content::Element(Element { name, .. }) => match name.deref() {
                    "head" => return painter.scope().trim(point(0, 0)),
                    "html" => {
                        let mut title = model.get_title();

                        if title.is_empty() {
                            title = "-untitled-".into();
                        }

                        let len = title.len() as u16;
                        dent = 0;
                        stack = stack.add_box(
                            Canvas::new(String::from(title).width(len))
                                .back(Color::rgb(0, 30, 0))
                                .front(Color::white())
                                .height(1)
                                .top(0),
                        )
                    }
                    _ => {
                        stack = stack.add_box(
                            Canvas::new(format!("{content}"))
                                .back(Color::black())
                                .front(Color::yellow(false))
                                .place()
                                .height(1)
                                .top(0),
                        )
                    }
                },
                Content::Document => dent = 0,
                Content::DocType { .. } => {}
                Content::Text { text } => {
                    stack = stack.add_box(text.trim().to_string().front(Color::white()));
                }
                _ => {
                    stack = stack.add_box(
                        Canvas::new(format!("{content}"))
                            .back(Color::black())
                            .front(Color::yellow(false))
                            .place()
                            .height(1)
                            .top(0),
                    )
                }
            };

            let mut content = Stack::south_east(vec![]);
            for handle in model.children(handle) {
                content = content.add_box(UiNode::new(handle))
            }

            self.ui = Box::new(stack.add_box(content.left(dent)));
            self.revision = model.revision();
        }
        self.ui.update(model, input, screen, painter)
    }
}