defmodule MyApp.Worker do
  use GenServer

  # api

  @spec start_link(worker_id :: String.t()) :: GenServer.on_start()
  def start_link(worker_id) do
    GenServer.start_link(__MODULE__, [worker_id], name: via_tuple(worker_id))
  end

  @spec child_spec([term()]) :: Supervisor.child_spec()
  def child_spec([worker_id]) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start_link, [worker_id]},
      restart: :transient
    }
  end

  @spec stop(worker_id :: String.t()) :: :ok
  def stop(worker_id) do
    # Given the :transient option in the child spec, the GenServer will restart
    # if any reason other than `:normal` is given.
    GenServer.stop(via_tuple(worker_id))
  end

  @spec ping(worker_id :: String.t()) :: :pong
  def ping(worker_id) do
     GenServer.call(via_tuple(worker_id), :ping)
  end

  # callbacks

  @impl true
  def init([worker_id]) do
    {:ok, %{id: worker_id}}
  end

  @impl true
  def handle_call(:ping, _from, state) do
    {:reply, :pong, state}
  end

  # internal

  @spec via_tuple(worker_id :: String.t()) :: {:via, Registry, {:worker_registry, worker_id :: String.t()}}
  defp via_tuple(worker_id), do: {:via, Registry, {:worker_registry, worker_id}}
end