defmodule Towerops.Snmp.Adapter do
  @moduledoc """
  Behavior for SNMP data sources.

  Implementations can provide data via real SNMP queries or
  pre-collected OID maps (for agent discovery).

  ## Usage

  Adapters enable existing discovery code to work with different data sources:
  - Real-time SNMP queries via SnmpKit
  - Pre-collected OID maps from remote agents (Replay adapter)
  - Test fixtures for testing

  ## Example

      # Using Replay adapter with agent data
      client_opts = [
        adapter: Towerops.Snmp.Adapters.Replay,
        oid_map: %{"1.3.6.1.2.1.1.1.0" => "Cisco IOS"},
        ip: device.ip_address
      ]

      {:ok, value} = Client.get(client_opts, "1.3.6.1.2.1.1.1.0")
  """

  @doc """
  Performs an SNMP GET operation for a single OID.

  ## Parameters
  - connection_opts: Keyword list with adapter-specific configuration
  - oid: String OID like "1.3.6.1.2.1.1.1.0"

  ## Returns
  - `{:ok, value}` on success where value is the extracted SNMP value
  - `{:error, reason}` on failure (e.g., `:no_such_name`, `:timeout`)
  """
  @callback get(connection_opts :: keyword(), oid :: String.t()) ::
              {:ok, term()} | {:error, term()}

  @doc """
  Performs an SNMP WALK operation starting from base_oid.

  Returns all OIDs that are descendants of the base OID.

  ## Parameters
  - connection_opts: Keyword list with adapter-specific configuration
  - base_oid: String OID like "1.3.6.1.2.1.2.2.1.1" (base of walk)

  ## Returns
  - `{:ok, list}` where list is `[{oid :: String.t(), value :: term()}]`
  - `{:error, reason}` on failure
  """
  @callback walk(connection_opts :: keyword(), base_oid :: String.t()) ::
              {:ok, [{oid :: String.t(), value :: term()}]} | {:error, term()}

  @doc """
  Performs multiple SNMP GET operations at once.

  ## Parameters
  - connection_opts: Keyword list with adapter-specific configuration
  - oids: List of string OIDs

  ## Returns
  - `{:ok, map}` where map is `%{oid => value}`
  - `{:error, reason}` on failure
  """
  @callback get_multiple(connection_opts :: keyword(), oids :: [String.t()]) ::
              {:ok, %{String.t() => term()}} | {:error, term()}
end
