use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;
use freya_elements::events::MouseEvent;
use freya_hooks::{
    use_animation_with_dependencies, use_applied_theme, use_node, use_platform, AccordionTheme,
    AccordionThemeWith, AnimNum,
};
use winit::window::CursorIcon;
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum AccordionStatus {
    #[default]
    Idle,
    Hovering,
}
#[derive(Props, Clone, PartialEq)]
pub struct AccordionProps {
    pub theme: Option<AccordionThemeWith>,
    pub children: Element,
    pub summary: Element,
}
#[allow(non_snake_case)]
pub fn Accordion(props: AccordionProps) -> Element {
    let theme = use_applied_theme!(&props.theme, accordion);
    let mut open = use_signal(|| false);
    let (node_ref, size) = use_node();
    let animation = use_animation_with_dependencies(&size.area.height(), move |ctx, height| {
        ctx.with(AnimNum::new(0., height).time(200))
    });
    let mut status = use_signal(AccordionStatus::default);
    let platform = use_platform();
    let animation_value = animation.read().get().read().as_f32();
    let AccordionTheme {
        background,
        color,
        border_fill,
    } = theme;
    let onclick = move |_: MouseEvent| {
        open.toggle();
        if *open.read() {
            animation.read().start();
        } else {
            animation.read().reverse();
        }
    };
    use_drop(move || {
        if *status.read() == AccordionStatus::Hovering {
            platform.set_cursor(CursorIcon::default());
        }
    });
    let onmouseenter = move |_| {
        platform.set_cursor(CursorIcon::Pointer);
        status.set(AccordionStatus::Hovering);
    };
    let onmouseleave = move |_| {
        platform.set_cursor(CursorIcon::default());
        status.set(AccordionStatus::default());
    };
    rsx!(
        rect {
            onmouseenter,
            onmouseleave,
            overflow: "clip",
            color: "{color}",
            padding: "10",
            margin: "2 4",
            corner_radius: "6",
            width: "100%",
            height: "auto",
            background: "{background}",
            onclick,
            border: "1 solid {border_fill}",
            {&props.summary}
            rect {
                overflow: "clip",
                width: "100%",
                height: "{animation_value}",
                rect {
                    reference: node_ref,
                    height: "auto",
                    width: "100%",
                    {&props.children}
                }
            }
        }
    )
}
#[derive(Props, Clone, PartialEq)]
pub struct AccordionSummaryProps {
    children: Element,
}
#[allow(non_snake_case)]
pub fn AccordionSummary(props: AccordionSummaryProps) -> Element {
    rsx!({ props.children })
}
#[derive(Props, Clone, PartialEq)]
pub struct AccordionBodyProps {
    children: Element,
}
#[allow(non_snake_case)]
pub fn AccordionBody(props: AccordionBodyProps) -> Element {
    rsx!(rect {
        width: "100%",
        padding: "15 0 0 0",
        {props.children}
    })
}
#[cfg(test)]
mod test {
    use freya::prelude::*;
    use freya_testing::{launch_test, EventName, PlatformEvent};
    use winit::event::MouseButton;
    #[tokio::test]
    pub async fn accordion() {
        fn accordion_app() -> Element {
            rsx!(
                Accordion {
                    summary: rsx!(AccordionSummary {
                        label {
                            "Accordion Summary"
                        }
                    }),
                    AccordionBody {
                        label {
                            "Accordion Body"
                        }
                    }
                }
            )
        }
        let mut utils = launch_test(accordion_app);
        let root = utils.root();
        let content = root.get(0).get(1).get(0);
        let label = content.get(0);
        utils.wait_for_update().await;
        utils.wait_for_update().await;
        assert!(!label.is_visible());
        utils.push_event(PlatformEvent::Mouse {
            name: EventName::Click,
            cursor: (5., 5.).into(),
            button: Some(MouseButton::Left),
        });
        utils.wait_for_update().await;
        assert!(label.is_visible());
    }
}