use crate::{
    pre_hooks, unpack_named_slots,
    widget::{
        component::{
            containers::float_box::{
                FloatBoxChange, FloatBoxChangeMessage, FloatBoxNotifyProps, FloatBoxState,
            },
            interactive::{
                button::{ButtonNotifyMessage, ButtonNotifyProps, ButtonProps, use_button},
                navigation::{
                    NavSignal, NavTrackingNotifyMessage, NavTrackingNotifyProps, use_nav_item,
                    use_nav_tracking_self,
                },
            },
        },
        context::WidgetContext,
        node::WidgetNode,
        unit::area::AreaBoxNode,
        utils::Vec2,
    },
};

#[pre_hooks(use_button, use_nav_tracking_self)]
pub fn use_float_view_control(context: &mut WidgetContext) {
    context
        .props
        .write(ButtonNotifyProps(context.id.to_owned().into()));
    context
        .props
        .write(NavTrackingNotifyProps(context.id.to_owned().into()));

    context.life_cycle.unmount(|context| {
        context.signals.write(NavSignal::Unlock);
    });

    context.life_cycle.change(|context| {
        let Some(notify) = context
            .props
            .read_cloned_or_default::<FloatBoxNotifyProps>()
            .0
            .read()
        else {
            return;
        };
        let button = context.state.read_cloned_or_default::<ButtonProps>();
        let zoom = context.props.read_cloned_or_default::<FloatBoxState>().zoom;
        let scale = if zoom > 0.0 { 1.0 / zoom } else { 1.0 };

        for msg in context.messenger.messages {
            if let Some(msg) = msg.as_any().downcast_ref::<ButtonNotifyMessage>() {
                if msg.trigger_start() {
                    context.signals.write(NavSignal::Lock);
                }
                if msg.trigger_stop() {
                    context.signals.write(NavSignal::Unlock);
                }
            } else if let Some(msg) = msg.as_any().downcast_ref::<NavTrackingNotifyMessage>()
                && button.selected
                && button.trigger
            {
                let delta = msg.pointer_delta_ui_space();
                context.messenger.write(
                    notify.clone(),
                    FloatBoxChangeMessage {
                        sender: context.id.to_owned(),
                        change: FloatBoxChange::RelativePosition(Vec2 {
                            x: delta.x * scale,
                            y: delta.y * scale,
                        }),
                    },
                );
            }
        }
    });
}

#[pre_hooks(use_nav_item, use_float_view_control)]
pub fn float_view_control(mut context: WidgetContext) -> WidgetNode {
    let WidgetContext {
        id,
        props,
        state,
        named_slots,
        ..
    } = context;
    unpack_named_slots!(named_slots => content);

    if let Some(p) = content.props_mut() {
        p.merge_from(props.clone());
        p.write(state.read_cloned_or_default::<ButtonProps>());
    }

    AreaBoxNode {
        id: id.to_owned(),
        slot: Box::new(content),
    }
    .into()
}
