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