Untitled-1
defmodule Horionos.Services.RateLimiter do
  @moduledoc """
  Rate limiter service.
  """
  use GenServer
  @callback check_rate(String.t(), integer(), integer()) :: :ok | :error
  @table_name :rate_limiter
  @spec start_link(any()) :: :ignore | {:error, any()} | {:ok, pid()}
  #
  def start_link(_opts) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end
  @spec init(any()) :: {:ok, map()}
  #
  def init(_) do
    :ets.new(@table_name, [:set, :named_table, :public, read_concurrency: true])
    {:ok, %{}}
  end
  @doc """
  Checks if the action is allowed based on the given key, limit, and time window.
  ## Parameters
    - key: A unique identifier for the action (e.g., "confirmation_instructions:user@example.com")
    - limit: The maximum number of actions allowed within the time window
    - window: The time window in milliseconds
  ## Returns
    - :ok if the action is allowed
    - :error if the rate limit has been exceeded
  """
  @spec check_rate(String.t(), integer(), integer()) :: :ok | :error
  #
  def check_rate(key, limit, window) do
    now = System.system_time(:millisecond)
    case :ets.lookup(@table_name, key) do
      [{^key, _count, last_reset}] when now - last_reset > window ->
        :ets.insert(@table_name, {key, 1, now})
        :ok
      [{^key, count, _last_reset}] when count >= limit ->
        :error
      [{^key, _count, _last_reset}] ->
        :ets.update_counter(@table_name, key, {2, 1})
        :ok
      [] ->
        :ets.insert(@table_name, {key, 1, now})
        :ok
    end
  end
end