lib/mixpanel/http/httpc.ex

if Code.ensure_loaded?(:httpc) do
  defmodule Mixpanel.HTTP.HTTPC do
    @moduledoc """
    Adapter for [httpc](http://erlang.org/doc/man/httpc.html).

    This is the default adapter.
    """

    @behaviour Mixpanel.HTTP

    @impl Mixpanel.HTTP
    @spec get(url :: String.t(), headers :: [{String.t(), binary}], opts :: keyword) ::
            {:ok, status :: 200..599, headers :: [{String.t(), binary}], body :: term}
            | {:error, String.t()}
    def get(url, headers, opts) do
      request(:get, url, headers, "", opts)
    end

    @impl Mixpanel.HTTP
    @spec post(
            url :: String.t(),
            body :: binary,
            headers :: [{String.t(), binary}],
            opts :: keyword
          ) ::
            {:ok, status :: 200..599, headers :: [{String.t(), binary}], body :: term}
            | {:error, String.t()}
    def post(url, body, headers, opts) do
      request(:post, url, headers, body, opts)
    end

    defp request(method, url, headers, payload, opts) do
      content_type =
        case List.keyfind(headers, "Content-Type", 0) do
          {_, value} -> to_charlist(value)
          _ -> nil
        end

      http_opts =
        opts
        |> Keyword.split([:insecure])
        |> then(fn {opts, _} -> opts end)
        |> Enum.reduce([], fn
          {:insecure, true}, acc ->
            [{:ssl, [{:verify, :verify_none}]} | acc]
        end)

      case do_request(
             method,
             url,
             prepare_headers(headers),
             content_type,
             payload,
             [{:autoredirect, false} | http_opts]
           ) do
        {:ok, {{_, status_code, _}, headers, body}} ->
          {:ok, status_code, format_headers(headers), to_string(body)}

        {:error, reason} ->
          {:error, to_string(reason)}
      end
    end

    defp do_request(:get, url, headers, _content_type, _payload, http_opts) do
      :httpc.request(:get, {url, headers}, http_opts, [])
    end

    defp do_request(:post, url, headers, content_type, payload, http_opts) do
      :httpc.request(:post, {url, headers, content_type, payload}, http_opts, [])
    end

    defp format_headers(headers) do
      for {key, value} <- headers do
        {to_string(key), to_string(value)}
      end
    end

    defp prepare_headers(headers) do
      for {key, value} <- headers do
        {to_charlist(key), to_charlist(value)}
      end
    end
  end
end