defmodule PhoenixLiveState.LiveView.Hooks do
  @moduledoc """
  Integration for clients.

  Clients are usually LiveView processes that want to share state with other
  LiveView processes.
  """
  @moduledoc since: "0.1.0"

  require Logger

  @doc since: "0.1.0"
  defmacro __using__(opts) do
    state_spec = Keyword.fetch!(opts, :live_state)

    quote do
      # Add a hook to the mount/3 callback so we can inject the live state configuration
      Phoenix.LiveView.on_mount(
        {PhoenixLiveState.LiveView.Hooks, {:live_state, [state_spec: unquote(state_spec)]}}
      )
    end
  end

  @doc since: "0.1.0"
  def on_mount({:live_state, args}, _params, _session, socket) do
    {:cont,
     socket
     |> Phoenix.LiveView.put_private(:live_state, args)
     |> Phoenix.LiveView.attach_hook(:live_state_broadcast, :handle_info, &handle_info/2)}
  end

  @doc since: "0.1.0"
  def handle_info({PhoenixLiveState, _server_key, event}, socket) do
    live_assigns = socket.assigns.live_assigns

    new_live_assigns =
      case event do
        {:new, key, value} -> Map.put(live_assigns, key, value)
        {:updated, key, value} -> Map.put(live_assigns, key, value)
        {:deleted, key} -> Map.delete(live_assigns, key)
        {:reset, fresh_state} -> fresh_state
      end

    {:halt, Phoenix.Component.assign(socket, :live_assigns, new_live_assigns)}
  end
end
