use super::space::ScreenValue;
use crate::ui::UIWidget;
use maud::{Markup, Render, html};

#[allow(non_snake_case)]
pub fn Padding<T: UIWidget + 'static>(inner: T) -> PaddingWidget {
    PaddingWidget {
        inner: Box::new(inner),
        all: None,
        x: None,
        y: None,
        start: None,
        end: None,
        top: None,
        right: None,
        bottom: None,
        left: None,
    }
}

pub struct PaddingWidget {
    pub inner: Box<dyn UIWidget>,
    pub all: Option<ScreenValue>,
    pub x: Option<ScreenValue>,
    pub y: Option<ScreenValue>,
    pub start: Option<ScreenValue>,
    pub end: Option<ScreenValue>,
    pub top: Option<ScreenValue>,
    pub right: Option<ScreenValue>,
    pub bottom: Option<ScreenValue>,
    pub left: Option<ScreenValue>,
}

impl PaddingWidget {
    #[must_use]
    pub const fn all(mut self, all: ScreenValue) -> Self {
        self.all = Some(all);
        self
    }

    #[must_use]
    pub const fn top(mut self, top: ScreenValue) -> Self {
        self.top = Some(top);
        self
    }

    #[must_use]
    pub const fn right(mut self, right: ScreenValue) -> Self {
        self.right = Some(right);
        self
    }

    #[must_use]
    pub const fn bottom(mut self, bottom: ScreenValue) -> Self {
        self.bottom = Some(bottom);
        self
    }

    #[must_use]
    pub const fn left(mut self, left: ScreenValue) -> Self {
        self.left = Some(left);
        self
    }

    #[must_use]
    pub const fn y(mut self, y: ScreenValue) -> Self {
        self.y = Some(y);
        self
    }

    #[must_use]
    pub const fn x(mut self, x: ScreenValue) -> Self {
        self.x = Some(x);
        self
    }
}

impl Render for PaddingWidget {
    fn render(&self) -> Markup {
        self.render_with_class("")
    }
}

impl UIWidget for PaddingWidget {
    fn can_inherit(&self) -> bool {
        true
    }

    fn base_class(&self) -> Vec<String> {
        let mut our_class = Vec::new();

        if let Some(all) = &self.all {
            our_class.push(format!("p-{}", all.to_value()));
        }

        if let Some(x) = &self.x {
            our_class.push(format!("px-{}", x.to_value()));
        }

        if let Some(y) = &self.y {
            our_class.push(format!("py-{}", y.to_value()));
        }

        if let Some(start) = &self.start {
            our_class.push(format!("ps-{}", start.to_value()));
        }

        if let Some(end) = &self.end {
            our_class.push(format!("pe-{}", end.to_value()));
        }

        if let Some(top) = &self.top {
            our_class.push(format!("pt-{}", top.to_value()));
        }

        if let Some(right) = &self.right {
            our_class.push(format!("pr-{}", right.to_value()));
        }

        if let Some(bottom) = &self.bottom {
            our_class.push(format!("pb-{}", bottom.to_value()));
        }

        if let Some(left) = &self.left {
            our_class.push(format!("pl-{}", left.to_value()));
        }

        our_class
    }

    fn extended_class(&self) -> Vec<String> {
        let mut c = self.base_class();
        c.extend_from_slice(&self.inner.extended_class());
        c
    }

    fn render_with_class(&self, class: &str) -> Markup {
        if self.inner.as_ref().can_inherit() {
            self.inner
                .as_ref()
                .render_with_class(&format!("{} {class}", self.base_class().join(" ")))
        } else {
            html! {
                div class=(format!("{} {class}", self.base_class().join(" "))) {
                    (self.inner.as_ref())
                }
            }
        }
    }
}