lib/circlex/emulator/logic/logic_util.ex

defmodule Circlex.Emulator.Logic.LogicUtil do
  @moduledoc """
  Helper functions for common logic utilities.
  """

  alias Circlex.Struct.{Payout, Transfer}

  def update(els, find_fn, update_fn, allow_nop \\ false) do
    case Enum.find_index(els, find_fn) do
      nil ->
        if allow_nop do
          {:ok, els}
        else
          :not_found
        end

      index ->
        el = Enum.at(els, index)

        case update_fn.(el) do
          nil ->
            {:ok, List.delete_at(els, index)}

          new_val ->
            {:ok, List.replace_at(els, index, new_val)}
        end
    end
  end

  def update_or_add(els, find_fn, update_fn) do
    case Enum.find_index(els, find_fn) do
      nil ->
        [update_fn.(nil) | els]

      index ->
        el = Enum.at(els, index)
        List.replace_at(els, index, update_fn.(el))
    end
  end

  def find(arr, finder) do
    case Enum.find(arr, finder) do
      nil ->
        :not_found

      val ->
        {:ok, val}
    end
  end

  def find!(arr, finder) do
    {:ok, val} = find(arr, finder)
    val
  end

  defp test_filter(payout = %Payout{}, {:source_wallet_id, source_wallet_id}) do
    payout.source_wallet_id == source_wallet_id
  end

  defp test_filter(transfer = %Transfer{}, {:transfer_source, {type, id}}) do
    transfer.source.type == type and transfer.source.id == id
  end

  def apply_filters(vals, filters) do
    Enum.filter(vals, fn val ->
      Enum.all?(filters, fn filter -> test_filter(val, filter) end)
    end)
  end

  def add_currencies(x, y) do
    Decimal.new(x)
    |> Decimal.add(Decimal.new(y))
    |> Decimal.to_string()
  end
end