defmodule Bot.Cache do
  # import Enum
  use Agent, restart: :permanent

  def start_link(opts) do
    Agent.start_link(&init/0, [{:name, __MODULE__} | opts])
  end

  # @impl true
  def init() do
    table = :ets.new(Bot.Cache, [:named_table, :public])
    {:ok, table}
  end

  # @type resource :: %{
  #         (id_literal :: String.t()) => String.t() | pos_integer(),
  #         String.t() => resource() | value() | [resource() | value()]
  #       }
  # @type value :: String.t() | number()

  # @spec insert(resource) :: :ok
  # def insert(resource) do
  #   reources = decompose_resource(resource)

  #   timestamped_resources = map(reources, &make_timestamped(&1, System.system_time(:second)))

  #   each(timestamped_resources, fn res -> :ok = GenServer.call(__MODULE__, {:merge, res}) end)
  #   :ok
  # end

  # defguardp is_resource(val) when is_map_key(val, "id")

  # defguardp is_value(val)
  #           when is_number(val) or is_binary(val) or (is_map(val) and not is_map_key(val, "id"))

  # defp res_or_val(x) when is_resource(x), do: :res
  # defp res_or_val(x) when is_value(x), do: :val

  # def decompose_resource(%{"id" => id} = res) do
  #   other_resources =
  #     flat_map(res, fn
  #       {_key, val} when is_resource(val) ->
  #         decompose_resource(val)

  #       {_key, val_list} when is_list(val_list) ->
  #         if val_list |> map(&res_or_val/1) |> all?(&(&1 == :res)) do
  #           flat_map(val_list, &decompose_resource/1)
  #         else
  #           true = val_list |> map(&res_or_val/1) |> all?(&(&1 == :val))
  #           []
  #         end

  #       {_key, val} when is_value(val) ->
  #         []
  #     end)

  #   stripped_res =
  #     flat_map(res, fn
  #       {key, %{"id" => id} = val} when is_resource(val) ->
  #         [{key <> "_id", to_int(id)}]

  #       {key, val_list} when is_list(val_list) ->
  #         if val_list |> map(&res_or_val/1) |> all?(&(&1 == :res)) do
  #           [{key, flat_map(val_list, fn %{"id" => id} -> [{key <> "_id", to_int(id)}] end)}]
  #         else
  #           true = val_list |> map(&res_or_val/1) |> all?(&(&1 == :val))
  #           [{key, val_list}]
  #         end

  #       {key, val} when is_value(val) ->
  #         [{key, val}]
  #     end)
  #     |> into(%{})

  #   [{to_int(id), stripped_res} | other_resources]
  # end

  # defp make_timestamped(x, ts) when is_map(x) do
  #   x |> map(fn {key, val} -> {key, make_timestamped(val, ts)} end) |> into(%{})
  # end

  # defp make_timestamped(x, ts) when is_number(x) or is_binary(x) do
  #   {ts, x}
  # end

  # defp make_timestamped(x, ts) when is_list(x) do
  #   map(x, &make_timestamped(&1, ts))
  # end

  # defp to_int(snowflake) when is_integer(snowflake) do
  #   snowflake
  # end

  # defp to_int(snowflake) when is_binary(snowflake) do
  #   String.to_integer(snowflake)
  # end

  # def handle_call({:merge, res}, _, table) do
  #   :ets.l()
  # end
end
