use gpui::{AnyElement, ClickEvent, prelude::*};

use crate::{ButtonLike, CommonAnimationExt, Tooltip, prelude::*};

/// A button component displayed in the title bar to show auto-update status.
#[derive(IntoElement, RegisterComponent)]
pub struct UpdateButton {
    icon: IconName,
    icon_animate: bool,
    icon_color: Option<Color>,
    message: SharedString,
    tooltip: Option<SharedString>,
    show_dismiss: bool,
    on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
    on_dismiss: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
}

impl UpdateButton {
    pub fn new(icon: IconName, message: impl Into<SharedString>) -> Self {
        Self {
            icon,
            icon_animate: false,
            icon_color: None,
            message: message.into(),
            tooltip: None,
            show_dismiss: false,
            on_click: None,
            on_dismiss: None,
        }
    }

    /// Sets whether the icon should have a rotation animation (for progress states).
    pub fn icon_animate(mut self, animate: bool) -> Self {
        self.icon_animate = animate;
        self
    }

    /// Sets the icon color (e.g., for warning/error states).
    pub fn icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
        self.icon_color = color.into();
        self
    }

    /// Sets the tooltip text shown on hover.
    pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
        self.tooltip = Some(tooltip.into());
        self
    }

    /// Shows a dismiss button on the right side.
    pub fn with_dismiss(mut self) -> Self {
        self.show_dismiss = true;
        self
    }

    /// Sets the click handler for the main button area.
    pub fn on_click(
        mut self,
        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
    ) -> Self {
        self.on_click = Some(Box::new(handler));
        self
    }

    /// Sets the click handler for the dismiss button.
    pub fn on_dismiss(
        mut self,
        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
    ) -> Self {
        self.on_dismiss = Some(Box::new(handler));
        self
    }

    pub fn checking() -> Self {
        Self::new(IconName::ArrowCircle, "Checking for app updates…").icon_animate(true)
    }

    pub fn downloading(version: impl Into<SharedString>) -> Self {
        Self::new(IconName::Download, "Downloading app update…").tooltip(version)
    }

    pub fn installing(version: impl Into<SharedString>) -> Self {
        Self::new(IconName::ArrowCircle, "Installing app update…")
            .icon_animate(true)
            .tooltip(version)
    }

    pub fn updated(version: impl Into<SharedString>) -> Self {
        Self::new(IconName::Download, "Restart to Update")
            .tooltip(version)
            .with_dismiss()
    }

    pub fn errored(error: impl Into<SharedString>) -> Self {
        Self::new(IconName::Warning, "Failed to update the app")
            .icon_color(Color::Warning)
            .tooltip(error)
            .with_dismiss()
    }
}

impl RenderOnce for UpdateButton {
    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
        let border_color = cx.theme().colors().border;

        let icon = Icon::new(self.icon)
            .size(IconSize::XSmall)
            .when_some(self.icon_color, |this, color| this.color(color));
        let icon_element = if self.icon_animate {
            icon.with_rotate_animation(3).into_any_element()
        } else {
            icon.into_any_element()
        };

        let tooltip = self.tooltip.clone();

        h_flex()
            .mr_2()
            .rounded_sm()
            .border_1()
            .border_color(border_color)
            .child(
                ButtonLike::new("update-button")
                    .child(
                        h_flex()
                            .h_full()
                            .gap_1()
                            .child(icon_element)
                            .child(Label::new(self.message).size(LabelSize::Small)),
                    )
                    .when_some(tooltip, |this, tooltip| {
                        this.tooltip(Tooltip::text(tooltip))
                    })
                    .when_some(self.on_click, |this, handler| this.on_click(handler)),
            )
            .when(self.show_dismiss, |this| {
                this.child(
                    div().border_l_1().border_color(border_color).child(
                        IconButton::new("dismiss-update-button", IconName::Close)
                            .icon_size(IconSize::Indicator)
                            .when_some(self.on_dismiss, |this, handler| this.on_click(handler))
                            .tooltip(Tooltip::text("Dismiss")),
                    ),
                )
            })
    }
}

impl Component for UpdateButton {
    fn scope() -> ComponentScope {
        ComponentScope::Collaboration
    }

    fn name() -> &'static str {
        "UpdateButton"
    }

    fn description() -> Option<&'static str> {
        Some(
            "A button component displayed in the title bar to show auto-update status and allow users to restart the app.",
        )
    }

    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
        let version = "1.99.0";

        Some(
            v_flex()
                .gap_6()
                .children(vec![
                    example_group_with_title(
                        "Progress States",
                        vec![
                            single_example("Checking", UpdateButton::checking().into_any_element()),
                            single_example(
                                "Downloading",
                                UpdateButton::downloading(version).into_any_element(),
                            ),
                            single_example(
                                "Installing",
                                UpdateButton::installing(version).into_any_element(),
                            ),
                        ],
                    ),
                    example_group_with_title(
                        "Actionable States",
                        vec![
                            single_example(
                                "Ready to Update",
                                UpdateButton::updated(version).into_any_element(),
                            ),
                            single_example(
                                "Error",
                                UpdateButton::errored("Network timeout").into_any_element(),
                            ),
                        ],
                    ),
                ])
                .into_any_element(),
        )
    }
}
