# `VirtualTimeGenStateMachine`
[🔗](https://github.com/d-led/gen_server_virtual_time/blob/v1.0.1/packages/gen_server_virtual_time/lib/virtual_time_gen_state_machine.ex#L1)

Use `VirtualTimeGenStateMachine` instead of `:gen_statem` to test timeouts and
timers without waiting for them.

This module wraps OTP's `:gen_statem` and provides `send_after/3`, which
schedules against either real time (production) or a virtual clock (testing).
The callback contract is `:gen_statem`'s: `init/1`, `handle_event/4` or state
functions, `terminate/3`, and so on.

## Example

    defmodule MyStateMachine do
      use VirtualTimeGenStateMachine, callback_mode: :handle_event_function

      def start_link(opts) do
        VirtualTimeGenStateMachine.start_link(__MODULE__, :off, opts)
      end

      @impl true
      def init(_) do
        {:ok, :off, %{count: 0}}
      end

      @impl true
      def handle_event(:cast, :flip, :off, data) do
        schedule_timer(100)
        {:next_state, :on, %{data | count: data.count + 1}}
      end

      @impl true
      def handle_event(:cast, :flip, :on, data) do
        {:next_state, :off, data}
      end

      @impl true
      def handle_event(:info, :timeout, _state, data) do
        {:keep_state, %{data | timeout_fired: true}}
      end

      defp schedule_timer(delay) do
        VirtualTimeGenStateMachine.send_after(self(), :timeout, delay)
      end
    end

## Testing with a local virtual clock

    test "state machine with timers" do
      {:ok, clock} = VirtualClock.start_link()

      {:ok, server} = MyStateMachine.start_link(virtual_clock: clock)

      # Trigger state transition
      VirtualTimeGenStateMachine.cast(server, :flip)

      # Advance virtual time - timer fires instantly
      VirtualClock.advance(clock, 100)

      # Check that timeout fired
      assert get_timeout_fired(server) == true
    end

# `call`

Makes a synchronous call to a state machine.

# `cancel_timer`

Cancels a timer created with send_after/3.
Uses the appropriate backend based on the current process configuration.

# `cast`

Sends an asynchronous cast to a state machine.

# `get_time_backend`

Gets the current time backend.

# `send_after`

Sends a message to a process after a delay in milliseconds.
Uses the appropriate backend based on the current process configuration.

# `send_immediately`

Sends a message immediately in virtual time.

With virtual time, this schedules the message for the current virtual time,
ensuring it gets processed in the next event cycle.
With real time, this sends the message immediately.

This is useful for triggering immediate responses or state changes
within the virtual time simulation.

## Examples

    # Send immediate message to self
    VirtualTimeGenStateMachine.send_immediately(self(), :process_now)

    # Send immediate message to another process
    VirtualTimeGenStateMachine.send_immediately(other_pid, {:urgent, data})

# `set_virtual_clock`

Sets the virtual clock for the current process.
All child processes will inherit this setting.

# `set_virtual_clock`

Sets the virtual clock for the current process without emitting warnings.

Use this when you intentionally want global virtual clock behavior and understand
the implications. The explanation message should describe why global clock is needed.

## Example

    iex> {:ok, clock} = VirtualClock.start_link()
    iex> VirtualTimeGenStateMachine.set_virtual_clock(clock, :i_know_what_i_am_doing, "coordinated simulation")
    VirtualTimeBackend

# `sleep`

Sleeps for the specified duration in milliseconds.
Uses the appropriate backend based on the current process configuration.

# `start`

Starts a GenStateMachine without linking.

# `start_link`

Starts a GenStateMachine with virtual time support.

Returns {:ok, pid, backend} where backend is the time backend to use.
Store the backend in your process state for optimal performance.

# `stop`

Stops a state machine.

# `use_real_time`

Uses real time (default behavior).

# `use_real_time`

Uses real time without emitting warnings.

Use this when you intentionally want global real time behavior and understand
the implications. The explanation message should describe why global real time is needed.

## Example

    iex> VirtualTimeGenStateMachine.use_real_time(:i_know_what_i_am_doing, "production mode")
    RealTimeBackend

---

*Consult [api-reference.md](api-reference.md) for complete listing*
