defmodule Towerops.Snmp.Poller do
  @moduledoc """
  SNMP polling functions for monitoring device reachability.

  Instead of pinging, SNMP-enabled devices are checked by polling sysUpTime.0,
  which provides both connectivity confirmation and device uptime information.
  """

  @behaviour Towerops.Snmp.PollerBehaviour

  alias Towerops.Snmp.Client

  require Logger

  @doc """
  Checks if an SNMP device is reachable by querying sysUpTime.0.

  Returns:
  - `{:ok, response_time_ms}` if successful
  - `{:error, reason}` if the check failed

  ## Examples

      iex> check_device(ip: "192.168.1.1", community: "public", version: "2c", port: 161)
      {:ok, 42.3}

      iex> check_device(ip: "192.168.1.99", community: "wrong", version: "2c", port: 161)
      {:error, :timeout}
  """
  @impl true
  @spec check_device(Client.connection_opts()) :: {:ok, integer()} | {:error, term()}
  def check_device(client_opts) do
    start_time = System.monotonic_time(:millisecond)

    case Client.get(client_opts, "1.3.6.1.2.1.1.3.0") do
      {:ok, _uptime} ->
        end_time = System.monotonic_time(:millisecond)
        response_time = end_time - start_time
        {:ok, response_time}

      {:error, reason} = error ->
        Logger.debug("SNMP check failed: #{inspect(reason)}")
        error
    end
  end

  @doc """
  Builds client options from device record.
  """
  @impl true
  @spec build_client_opts(map()) :: Client.connection_opts()
  def build_client_opts(device) do
    [
      ip: device.ip_address,
      community: device.snmp_community,
      version: device.snmp_version,
      port: device.snmp_port || 161,
      timeout: 5000
    ]
  end
end
