//! wlr-virtual-pointer-unstable-v1 protocol implementation.
//!
//! Allows clients to create software pointer devices for input injection,
//! used by remote desktop, accessibility tools, and testing frameworks.

use smithay::reexports::wayland_protocols_wlr::virtual_pointer::v1::server::{
    zwlr_virtual_pointer_manager_v1::{self, ZwlrVirtualPointerManagerV1},
    zwlr_virtual_pointer_v1::{self, ZwlrVirtualPointerV1},
};
use smithay::reexports::wayland_server::{
    Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New,
};
use tracing::{debug, trace};

const MANAGER_VERSION: u32 = 1;

pub struct VirtualPointerManagerState;

impl VirtualPointerManagerState {
    pub fn new<D>(display: &DisplayHandle) -> Self
    where
        D: GlobalDispatch<ZwlrVirtualPointerManagerV1, ()>
            + Dispatch<ZwlrVirtualPointerManagerV1, ()>
            + Dispatch<ZwlrVirtualPointerV1, ()>
            + 'static,
    {
        display.create_global::<D, ZwlrVirtualPointerManagerV1, _>(MANAGER_VERSION, ());
        Self
    }
}

impl<D> GlobalDispatch<ZwlrVirtualPointerManagerV1, (), D> for VirtualPointerManagerState
where
    D: GlobalDispatch<ZwlrVirtualPointerManagerV1, ()>
        + Dispatch<ZwlrVirtualPointerManagerV1, ()>
        + Dispatch<ZwlrVirtualPointerV1, ()>
        + 'static,
{
    fn bind(
        _state: &mut D,
        _display: &DisplayHandle,
        _client: &Client,
        resource: New<ZwlrVirtualPointerManagerV1>,
        _data: &(),
        data_init: &mut DataInit<'_, D>,
    ) {
        data_init.init(resource, ());
        debug!("wlr-virtual-pointer-manager bound");
    }
}

impl<D> Dispatch<ZwlrVirtualPointerManagerV1, (), D> for VirtualPointerManagerState
where
    D: Dispatch<ZwlrVirtualPointerManagerV1, ()>
        + Dispatch<ZwlrVirtualPointerV1, ()>
        + 'static,
{
    fn request(
        _state: &mut D,
        _client: &Client,
        _resource: &ZwlrVirtualPointerManagerV1,
        request: zwlr_virtual_pointer_manager_v1::Request,
        _data: &(),
        _display: &DisplayHandle,
        data_init: &mut DataInit<'_, D>,
    ) {
        match request {
            zwlr_virtual_pointer_manager_v1::Request::CreateVirtualPointer { seat: _, id } => {
                data_init.init(id, ());
                debug!("Virtual pointer created");
            }
            zwlr_virtual_pointer_manager_v1::Request::CreateVirtualPointerWithOutput {
                seat: _,
                output: _,
                id,
            } => {
                data_init.init(id, ());
                debug!("Virtual pointer created (with output)");
            }
            zwlr_virtual_pointer_manager_v1::Request::Destroy => {}
            _ => {}
        }
    }
}

impl<D> Dispatch<ZwlrVirtualPointerV1, (), D> for VirtualPointerManagerState
where
    D: Dispatch<ZwlrVirtualPointerV1, ()> + 'static,
{
    fn request(
        _state: &mut D,
        _client: &Client,
        _resource: &ZwlrVirtualPointerV1,
        request: zwlr_virtual_pointer_v1::Request,
        _data: &(),
        _display: &DisplayHandle,
        _data_init: &mut DataInit<'_, D>,
    ) {
        match request {
            zwlr_virtual_pointer_v1::Request::Motion { time, dx, dy } => {
                trace!("vptr: motion time={time} dx={dx} dy={dy}");
                // Virtual pointer motion events are forwarded to the seat via
                // the compositor's input handling. The compositor reads pointer
                // events from libinput; virtual pointer events are accepted but
                // not injected into the libinput path — clients using this
                // protocol typically manage their own cursor drawing.
            }
            zwlr_virtual_pointer_v1::Request::MotionAbsolute {
                time,
                x,
                y,
                x_extent,
                y_extent,
            } => {
                trace!("vptr: abs motion time={time} x={x} y={y} ext={x_extent}x{y_extent}");
            }
            zwlr_virtual_pointer_v1::Request::Button {
                time,
                button,
                state,
            } => {
                trace!("vptr: button time={time} btn={button} state={state:?}");
            }
            zwlr_virtual_pointer_v1::Request::Axis {
                time,
                axis,
                value,
            } => {
                trace!("vptr: axis time={time} axis={axis:?} val={value}");
            }
            zwlr_virtual_pointer_v1::Request::Frame => {}
            zwlr_virtual_pointer_v1::Request::AxisSource { axis_source } => {
                trace!("vptr: axis source {axis_source:?}");
            }
            zwlr_virtual_pointer_v1::Request::AxisStop { time, axis } => {
                trace!("vptr: axis stop time={time} axis={axis:?}");
            }
            zwlr_virtual_pointer_v1::Request::AxisDiscrete {
                time,
                axis,
                value,
                discrete,
            } => {
                trace!("vptr: axis discrete time={time} axis={axis:?} val={value} disc={discrete}");
            }
            zwlr_virtual_pointer_v1::Request::Destroy => {}
            _ => {}
        }
    }
}

#[macro_export]
macro_rules! delegate_virtual_pointer {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            smithay::reexports::wayland_protocols_wlr::virtual_pointer::v1::server::zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1: ()
        ] => $crate::protocols::virtual_pointer::VirtualPointerManagerState);

        smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            smithay::reexports::wayland_protocols_wlr::virtual_pointer::v1::server::zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1: ()
        ] => $crate::protocols::virtual_pointer::VirtualPointerManagerState);

        smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            smithay::reexports::wayland_protocols_wlr::virtual_pointer::v1::server::zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1: ()
        ] => $crate::protocols::virtual_pointer::VirtualPointerManagerState);
    };
}
