defmodule Towerops.Workers.PollingOffset do
  @moduledoc """
  Calculates deterministic polling offsets to distribute load across time.

  Uses erlang's phash2 to generate stable offsets from device IDs,
  ensuring each device polls at a different time within the interval.

  This prevents the "thundering herd" problem where all devices poll
  at synchronized clock intervals (e.g., 1:00, 1:05, 1:10), creating
  load spikes on the server.

  ## Examples

      # Device with ID "abc-123" and 300-second interval
      iex> calculate_offset("abc-123", 300)
      94  # Device polls at :01:34, :06:34, :11:34, etc.

      # Same device always gets same offset
      iex> calculate_offset("abc-123", 300)
      94

      # Different device gets different offset
      iex> calculate_offset("def-456", 300)
      171  # Device polls at :02:51, :07:51, :12:51, etc.
  """

  @doc """
  Calculate polling offset for a device.

  Returns an offset in seconds between 0 and interval_seconds-1.
  Same device_id always returns same offset for a given interval.

  ## Parameters

    * `device_id` - The device UUID (binary or string format)
    * `interval_seconds` - The polling interval in seconds

  ## Returns

  An integer offset in the range [0, interval_seconds)

  ## Examples

      iex> calculate_offset("abc-123", 300)
      94

      iex> calculate_offset("abc-123", 300)
      94  # Always returns same value for same device

      iex> offset = calculate_offset("some-uuid", 60)
      iex> offset >= 0 and offset < 60
      true
  """
  @spec calculate_offset(binary(), pos_integer()) :: non_neg_integer()
  def calculate_offset(device_id, interval_seconds) do
    device_id |> :erlang.phash2() |> rem(interval_seconds)
  end
end
