Skip to main content

lib/reloop/support/parameters.ex

defmodule Reloop.Support.Parameters do
  @moduledoc false

  @request_key_map %{
    "first_name" => "firstName",
    "last_name" => "lastName",
    "group_ids" => "groupIds",
    "group_id" => "groupId",
    "fallback_value" => "fallbackValue",
    "default_subscription" => "defaultSubscription",
    "channel_id" => "channelId",
    "property_name" => "propertyName",
    "property_type" => "propertyType",
    "contact_id" => "contactId",
    "rate_limit_enabled" => "rateLimitEnabled",
    "user_id" => "userId"
  }

  @doc """
  Pass parameters through without camelCase conversion (domain API).
  Drops nil values.
  """
  def for_snake_request(params) when is_map(params) do
    params
    |> Enum.reject(fn {_key, value} -> is_nil(value) end)
    |> Map.new()
  end

  @doc """
  Normalize request/query parameters to camelCase for contacts and API key APIs.
  """
  def for_request(params) when is_map(params) do
    params
    |> Enum.reduce(%{}, fn {key, value}, acc ->
      key = to_string(key)

      cond do
        key == "unsubscribed" and not Map.has_key?(params, :status) and not Map.has_key?(params, "status") ->
          Map.put(acc, "status", if(value, do: "unsubscribed", else: "subscribed"))

        true ->
          api_key = Map.get(@request_key_map, key, to_camel_case(key))
          Map.put(acc, api_key, normalize_value(value, :request))
      end
    end)
    |> Enum.reject(fn {_key, value} -> is_nil(value) end)
    |> Map.new()
  end

  @doc """
  Build query params for GET requests. Drops nil values.
  """
  def for_query(options) when is_map(options) do
    for_request(options)
  end

  defp normalize_value(value, :request) when is_map(value) do
    if map_size(value) == 0 do
      value
    else
      keys = Map.keys(value)

      if Enum.all?(keys, &is_integer/1) do
        Enum.map(value, fn
          {_index, item} when is_map(item) -> normalize_value(item, :request)
          {_index, item} -> item
        end)
      else
        for_request(value)
      end
    end
  end

  defp normalize_value(value, _mode), do: value

  defp to_camel_case(key) do
    if String.contains?(key, "_") do
      [first | rest] = String.split(key, "_")
      first <> Enum.map_join(rest, "", &String.capitalize/1)
    else
      key
    end
  end
end