Skip to main content

lib/billdog_eng/messaging.ex

defmodule BilldogEng.Messaging do
  @moduledoc """
  Messaging dispatch (BillDog advantage over PostHog) — server-side delivery
  across push / email / sms / in-app / live-activity.

  Note: `messaging-dispatch` authenticates with a Supabase session **Bearer
  JWT** + project membership, not the `x-api-key` key used by the other modules.
  Pass the JWT as `:access_token` per call.

  Mirrors the Node SDK `messaging.ts`.
  """

  alias BilldogEng.Transport

  @doc """
  Dispatch a message. Returns `{:ok, %{"sent" => .., "failed" => ..}}` (or a
  `{:error, ...}` envelope when no recipients match).

  Required params (keyword list):

    * `:project_id`   — project UUID
    * `:channel`      — one of `push|email|sms|in-app|live-activity`
    * `:content`      — channel-specific content map
    * `:access_token` — Bearer JWT

  Optional: `:targeting`, `:scheduling`, `:template_id`.
  """
  @spec dispatch(BilldogEng.t(), keyword()) ::
          {:ok, term()} | {:error, BilldogEng.Error.t()}
  def dispatch(client, params) do
    body =
      %{
        action: "send",
        project_id: Keyword.fetch!(params, :project_id),
        channel: Keyword.fetch!(params, :channel),
        content: Keyword.fetch!(params, :content)
      }
      |> put_if(:targeting, Keyword.get(params, :targeting))
      |> put_if(:scheduling, Keyword.get(params, :scheduling))
      |> put_if(:template_id, Keyword.get(params, :template_id))

    access_token = Keyword.fetch!(params, :access_token)

    Transport.request(client.transport,
      path: "/messaging-dispatch",
      body: body,
      headers: [{"authorization", "Bearer #{access_token}"}],
      gzip: false
    )
  end

  defp put_if(map, _key, nil), do: map
  defp put_if(map, key, value), do: Map.put(map, key, value)
end