use super::UIWidget;
use maud::{Markup, PreEscaped, Render, html};

pub mod animation;
pub mod background;
pub mod border;
pub mod container;
pub mod cursor;
pub mod display;
pub mod div;
pub mod filter;
pub mod flex;
pub mod grid;
pub mod height;
pub mod image;
pub mod input;
pub mod link;
pub mod list;
pub mod margin;
pub mod padding;
pub mod position;
pub mod rounded;
pub mod scroll;
pub mod shadow;
pub mod sized;
pub mod space;
pub mod svg;
pub mod table;
pub mod text;
pub mod transform;
pub mod visibility;
pub mod width;

#[allow(non_snake_case)]
#[must_use]
pub fn Nothing() -> PreEscaped<String> {
    html! {}
}

#[allow(non_snake_case)]
#[must_use]
/// Create a new inheritance context
///
/// This acts as a hard barrier for inheritance.
/// This allows you to embed Widgets without them interacting with the rest of the tree.
pub fn Context<T: UIWidget>(inner: T) -> PreEscaped<String> {
    html! { (inner) }
}

/// Generates a `<script>` element containing the provided JavaScript code.
///
/// This function wraps the provided JavaScript code in a `<script>` tag,
/// allowing for easy inclusion of custom scripts in the rendered HTML.
///
/// # Arguments
/// * `script` - The JavaScript code to include.
///
/// # Returns
/// A `PreEscaped<String>` containing the rendered `<script>` element.
#[must_use]
pub fn script(script: &str) -> PreEscaped<String> {
    html!(
        script {
            (PreEscaped(script))
        };
    )
}

pub enum Size {
    Custom(String),
    None,
    Small,
    Regular,
    Medium,
    Large,
    XL,
    _2XL,
    _3XL,
    Full,
}

impl Size {
    #[must_use]
    pub const fn to_value(&self) -> &str {
        match self {
            Self::Custom(str) => str.as_str(),
            Self::None => "none",
            Self::Small => "sm",
            Self::Regular => "",
            Self::Medium => "md",
            Self::Large => "lg",
            Self::XL => "xl",
            Self::_2XL => "2xl",
            Self::_3XL => "3xl",
            Self::Full => "full",
        }
    }
}

pub enum Side {
    Start,
    End,
    Top,
    Right,
    Bottom,
    Left,
    StartStart,
    StartEnd,
    EndEnd,
    EndStart,
    TopLeft,
    TopRight,
    BottomRight,
    BottomLeft,
    Center,
}

impl Side {
    #[must_use]
    pub const fn to_value(&self) -> &str {
        match self {
            Self::Start => "s",
            Self::End => "e",
            Self::Top => "t",
            Self::Right => "r",
            Self::Bottom => "b",
            Self::Left => "l",
            Self::StartStart => "ss",
            Self::StartEnd => "se",
            Self::EndEnd => "ee",
            Self::EndStart => "es",
            Self::TopLeft => "tl",
            Self::TopRight => "tr",
            Self::BottomRight => "br",
            Self::BottomLeft => "bl",
            Self::Center => "center",
        }
    }
}

#[allow(non_snake_case)]
pub fn NoBrowserAppearance<T: UIWidget + 'static>(inner: T) -> NoBrowserAppearanceWidget {
    NoBrowserAppearanceWidget(Box::new(inner))
}

pub struct NoBrowserAppearanceWidget(Box<dyn UIWidget>);

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

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

    fn base_class(&self) -> Vec<String> {
        vec!["appearance-none".to_string()]
    }

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

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