defmodule GenDOM.Event do
  @moduledoc """
  Represents an event which takes place in the DOM.

  The Event interface represents an event which takes place in the DOM. An event can be triggered by the user action
  such as clicking the mouse button or pressing a key on the keyboard, or generated by APIs to represent the progress
  of an asynchronous task. It can also be triggered programmatically.
  """

  use GenObject, [
    # Instance properties
    bubbles: false,
    cancelable: false,
    composed: false,
    current_target: nil,
    default_prevented: false,
    event_phase: 0,
    is_trusted: false,
    stop_propagation: false,
    stop_immediate_propagation: false,
    target: nil,
    time_stamp: 0,
    type: ""
  ]

  @doc """
  Creates a new Event.

  The Event() constructor creates an Event object, returning it to the caller.

  ## Parameters

  - `type` - A string representing the name of the event
  - `options` - An optional keyword list containing:
    - `:bubbles` - Whether the event bubbles (default: false)  
    - `:cancelable` - Whether the event can be cancelled (default: false)
    - `:composed` - Whether the event triggers listeners outside a shadow root (default: false)

  ## Examples

      # Create a simple event
      event = GenDOM.Event.new("click")

      # Create an event that bubbles and can be cancelled
      event = GenDOM.Event.new("look", bubbles: true, cancelable: false)

      # Create an event with all options
      event = GenDOM.Event.new("custom", 
        bubbles: true, 
        cancelable: true, 
        composed: true
      )
  """
  def new(type, options \\ []) do
    case start([
      type: type,
      bubbles: Keyword.get(options, :bubbles, false),
      cancelable: Keyword.get(options, :cancelable, false),
      composed: Keyword.get(options, :composed, false),
      time_stamp: System.system_time(:millisecond)
    ]) do
      {:ok, pid} -> GenServer.call(pid, :get)
      _other -> {:error, "could not start"}
    end
  end
  defoverridable new: 1, new: 2

  @doc """
  Returns the event's path (objects on which listeners will be invoked).

  The composedPath() method returns an array of the objects on which listeners will be invoked.
  This does not include nodes in shadow trees if the shadow root was created with ShadowRoot.mode closed.
  """
  def composed_path(_event) do
    # Implementation would return event path
    []
  end

  @doc """
  Cancels the event if it is cancelable.

  The preventDefault() method tells the user agent that if the event does not get explicitly handled,
  its default action should not be taken as it normally would be.
  """
  def prevent_default(event) do
    merge_lazy(event, fn(event) ->
      if event.cancelable do
        %{
          default_prevented: true
        }
      else
        %{}
      end
    end)
  end

  @doc """
  Prevents other listeners of the same event from being called.

  The stopImmediatePropagation() method prevents other listeners of the same event from being called.
  If several listeners are attached to the same element for the same event type, they are called in the order
  in which they were added. If stopImmediatePropagation() is invoked during one such call,
  no remaining listeners will be called.
  """
  def stop_immediate_propagation(event) do
    set(event, :stop_immediate_propagation, true)
  end

  @doc """
  Prevents further propagation of the current event in the capturing and bubbling phases.

  The stopPropagation() method prevents further propagation of the current event in the capturing
  and bubbling phases. It does not, however, prevent any default behaviors from occurring.
  """
  def stop_propagation(event) do
    set(event, :stop_propagation, true)
  end
end
