lib/membership/member.server.ex

defmodule Membership.Member.Server do
  use GenServer

  @moduledoc """
  Service
    this will store the member state
  """

  @registry_name :active_memberships

  defstruct identifier: nil, features: []

  def child_spec(data) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start_link, [data]},
      type: :worker
    }
  end

  @impl true
  def init(init_arg) do
    {:ok, agent} = Agent.start_link(fn -> [] end)
    init_arg = Map.put(init_arg, :ref, agent)
    {:ok, init_arg}
  end

  def add_to_calculated_registry(member, data) do
    name = via_tuple(member.identifier)
    GenServer.call(name, {:add_to_calculated_registry, data})
  end

  def fetch_from_calculated_registry(member) do
    name = via_tuple(member.identifier)
    GenServer.call(name, :fetch_from_calculated_registry)
  end

  def fetch_from_calculated_registry(member, data) do
    name = via_tuple(member.identifier)
    GenServer.call(name, {:fetch_from_calculated_registry, data})
  end

  def start_link(data) do
    name = via_tuple(data.identifier)
    GenServer.start_link(__MODULE__, data, name: name)
  end

  def shutdown(data) do
    name = via_tuple(data.identifier)
    GenServer.call(name, :shutdown)
  end

  def shutdown() do
    GenServer.call(__MODULE__, :shutdown)
  end

  @impl true
  def handle_call(
        :shutdown,
        _from,
        state
      ) do
    {:stop, {:ok, "Normal Shutdown"}, state}
  end

  @impl true
  def handle_call({:add_to_calculated_registry, data}, _, state) do
    Agent.update(state.ref, fn _state -> [data] end)

    {:reply, state, state}
  end

  @impl true
  def handle_call({:fetch_from_calculated_registry, key}, _, state) do
    reply =
      Agent.get(state.ref, fn state ->
        Enum.find(state, fn {x, _} -> x == key end)
      end)

    reply =
      case reply do
        nil -> []
        _ -> reply
      end

    {:reply, reply, state}
  end

  @impl true
  def handle_call(:fetch_from_calculated_registry, _, state) do
    reply =
      Agent.get(state.ref, fn state -> state end)

    {:reply, reply, state}
  end

  @impl true
  def handle_call(_msg, _, state) do
    {:reply, state, state}
  end

  @impl true
  def handle_cast(
        :shutdown,
        state
      ) do
    {:stop, :normal, state}
  end

  @impl true
  def handle_cast({:update, data}, state) do
    data = Map.put(data, :ref, state.ref)
    {:noreply, data}
  end

  @doc false
  def via_tuple(id, registry \\ @registry_name) do
    {:via, Registry, {registry, id}}
  end

  @impl true
  def handle_info({:DOWN, _ref, :process, _pid, _reason}, data) do
    {:noreply, data}
  end

  @impl true
  def handle_info(_msg, state) do
    {:noreply, state}
  end

  def show(params) do
    GenServer.call(via_tuple(params.identifier), :show)
  end
end