module Selenium::WebDriver::PointerActions

def button_action(button, action, device: nil, **opts)

def button_action(button, action, device: nil, **opts)
  pointer = pointer_input(device)
  pointer.send(action, button, **opts)
  tick(pointer)
  self
end

def click(element = nil, button: nil, device: nil)

def click(element = nil, button: nil, device: nil)
  move_to(element, device: device) if element
  pointer_down(button || :left, device: device)
  pointer_up(button || :left, device: device)
  self
end

def click_and_hold(element = nil, button: nil, device: nil)

def click_and_hold(element = nil, button: nil, device: nil)
  move_to(element, device: device) if element
  pointer_down(button || :left, device: device)
  self
end

def context_click(element = nil, device: nil)

def context_click(element = nil, device: nil)
  click(element, button: :right, device: device)
end

def default_move_duration

def default_move_duration
  @default_move_duration ||= @duration / 1000.0 # convert ms to seconds
end

def double_click(element = nil, device: nil)

def double_click(element = nil, device: nil)
  move_to(element, device: device) if element
  click(device: device)
  click(device: device)
  self
end

def drag_and_drop(source, target, device: nil)

def drag_and_drop(source, target, device: nil)
  click_and_hold(source, device: device)
  move_to(target, device: device)
  release(device: device)
  self
end

def drag_and_drop_by(source, right_by, down_by, device: nil)

def drag_and_drop_by(source, right_by, down_by, device: nil)
  click_and_hold(source, device: device)
  move_by(right_by, down_by, device: device)
  release(device: device)
  self
end

def move_by(right_by, down_by, device: nil, duration: default_move_duration, **opts)

def move_by(right_by, down_by, device: nil, duration: default_move_duration, **opts)
  pointer = pointer_input(device)
  pointer.create_pointer_move(duration: duration,
                              x: Integer(right_by),
                              y: Integer(down_by),
                              origin: Interactions::PointerMove::POINTER,
                              **opts)
  tick(pointer)
  self
end

def move_to(element, right_by = nil, down_by = nil, **opts)

def move_to(element, right_by = nil, down_by = nil, **opts)
  pointer = pointer_input(opts.delete(:device))
  pointer.create_pointer_move(duration: opts.delete(:duration) || default_move_duration,
                              x: right_by || 0,
                              y: down_by || 0,
                              origin: element,
                              **opts)
  tick(pointer)
  self
end

def move_to_location(x, y, device: nil, duration: default_move_duration, **opts)

def move_to_location(x, y, device: nil, duration: default_move_duration, **opts)
  pointer = pointer_input(device)
  pointer.create_pointer_move(duration: duration,
                              x: Integer(x),
                              y: Integer(y),
                              origin: Interactions::PointerMove::VIEWPORT,
                              **opts)
  tick(pointer)
  self
end

def pointer_down(button = :left, device: nil, **opts)

def pointer_down(button = :left, device: nil, **opts)
  button_action(button, :create_pointer_down, device: device, **opts)
end

def pointer_input(name = nil)

def pointer_input(name = nil)
  device(name: name, type: Interactions::POINTER) || add_pointer_input(:mouse, 'mouse')
end

def pointer_up(button = :left, device: nil, **opts)

def pointer_up(button = :left, device: nil, **opts)
  button_action(button, :create_pointer_up, device: device, **opts)
end

def release(button: nil, device: nil)

def release(button: nil, device: nil)
  pointer_up(button || :left, device: device)
  self
end