use dioxus::prelude::*;

use crate::cn;

const ALERT_BASE: &str = "relative w-full rounded-lg border px-4 py-3 text-sm grid \
                          has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] \
                          has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 \
                          [&>svg]:text-current";
#[derive(Clone, Default, PartialEq)]
pub enum AlertVariant {
	#[default]
	Default,
	Destructive,
}

impl AlertVariant {
	fn class(&self) -> &'static str {
		match self {
			AlertVariant::Default => "bg-card text-card-foreground",
			AlertVariant::Destructive => "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
		}
	}
}

#[component]
pub fn Alert(#[props(default)] variant: AlertVariant, #[props(default)] class: String, children: Element) -> Element {
	let cls = cn!(ALERT_BASE, variant.class(), class);
	rsx! {
		div { class: cls, "data-slot": "alert", role: "alert", {children} }
	}
}

#[component]
pub fn AlertTitle(#[props(default)] class: String, children: Element) -> Element {
	let cls = cn!("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", class);
	rsx! {
		div { class: cls, "data-slot": "alert-title", {children} }
	}
}

#[component]
pub fn AlertDescription(#[props(default)] class: String, children: Element) -> Element {
	let cls = cn!("text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed", class);
	rsx! {
		div { class: cls, "data-slot": "alert-description", {children} }
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use crate::uikit::test_util::render;

	#[test]
	fn default_variant_renders_base_and_slot() {
		fn app() -> Element {
			rsx! { Alert { "body" } }
		}
		let html = render(app);
		assert!(html.contains("bg-card"), "{html}");
		assert!(html.contains("data-slot=\"alert\""), "{html}");
		assert!(html.contains("role=\"alert\""), "{html}");
		assert!(html.contains("body"));
	}

	#[test]
	fn destructive_variant() {
		fn app() -> Element {
			rsx! {
				Alert { variant: AlertVariant::Destructive, "x" }
			}
		}
		let html = render(app);
		assert!(html.contains("text-destructive"), "{html}");
	}

	#[test]
	fn title_and_description_slots() {
		fn app() -> Element {
			rsx! {
				Alert {
					AlertTitle { "t" }
					AlertDescription { "d" }
				}
			}
		}
		let html = render(app);
		assert!(html.contains("data-slot=\"alert-title\""), "{html}");
		assert!(html.contains("data-slot=\"alert-description\""), "{html}");
		assert!(html.contains("text-muted-foreground"), "{html}");
	}
}
