defmodule SnmpKit do
  @moduledoc """
  Unified API for SnmpKit - A comprehensive SNMP toolkit for Elixir.

  This module provides a clean, organized interface to all SnmpKit functionality
  through context-based sub-modules:

  - `SnmpKit.SNMP` - SNMP operations (get, walk, bulk, etc.)
  - `SnmpKit.MIB` - MIB compilation, loading, and resolution

  ## Timeout Behavior

  SnmpKit uses two types of timeouts:

  ### PDU Timeout (`:timeout` parameter)
  - Controls how long to wait for each individual SNMP PDU response
  - Default: 10 seconds for GET/GETBULK, 30 seconds for walks
  - Applied per SNMP packet, not per operation

  ### Task Timeout (internal)
  - Prevents operations from hanging indefinitely
  - GET/GETBULK: PDU timeout + 1 second (safeguard)
  - Walk operations: 20 minutes maximum (allows large table walks)

  ### Walk Operations
  Walk operations may send many GETBULK PDUs to retrieve all data:
  - Each PDU has its own timeout (PDU timeout)
  - Large tables may need 50-200+ PDUs
  - Total time = N_pdus × PDU_timeout (up to 20 minute maximum)

  ## Quick Examples

      # SNMP Operations
      {:ok, value} = SnmpKit.SNMP.get("192.168.1.1", "sysDescr.0")
      {:ok, results} = SnmpKit.SNMP.walk("192.168.1.1", "system")

      # With custom PDU timeout
      {:ok, value} = SnmpKit.SNMP.get("192.168.1.1", "sysDescr.0", timeout: 15_000)
      {:ok, results} = SnmpKit.SNMP.walk("192.168.1.1", "ifTable", timeout: 30_000)

      # MIB Operations
      {:ok, oid} = SnmpKit.MIB.resolve("sysDescr.0")
      {:ok, compiled} = SnmpKit.MIB.compile("MY-MIB.mib")

  For backward compatibility, many common operations are also available
  directly on the main SnmpKit module.
  """

  # Direct API for most common operations (backward compatibility)
  defdelegate get(target, oid), to: SnmpKit.SnmpMgr
  defdelegate get(target, oid, opts), to: SnmpKit.SnmpMgr
  defdelegate get_next(target, oid), to: SnmpKit.SnmpMgr
  defdelegate get_next(target, oid, opts), to: SnmpKit.SnmpMgr
  defdelegate walk(target, oid), to: SnmpKit.SnmpMgr
  defdelegate walk(target, oid, opts), to: SnmpKit.SnmpMgr
  defdelegate set(target, oid, value), to: SnmpKit.SnmpMgr
  defdelegate set(target, oid, value, opts), to: SnmpKit.SnmpMgr
  defdelegate resolve(name), to: SnmpKit.SnmpMgr.MIB

  # Bulk operations (top-level convenience)
  defdelegate get_bulk(target, oid_or_oids), to: SnmpKit.SnmpMgr
  defdelegate get_bulk(target, oid_or_oids, opts), to: SnmpKit.SnmpMgr
  defdelegate bulk_walk(target, root_oid), to: SnmpKit.SnmpMgr
  defdelegate bulk_walk(target, root_oid, opts), to: SnmpKit.SnmpMgr

  # Walk table convenience
  defdelegate walk_table(target, table_oid), to: SnmpKit.SnmpMgr
  defdelegate walk_table(target, table_oid, opts), to: SnmpKit.SnmpMgr

  defmodule SNMP do
    @moduledoc """
    SNMP client operations for querying and managing SNMP devices.

    This module provides all SNMP protocol operations including:
    - Basic operations: get, set, get_next
    - Bulk operations: get_bulk, walk, table operations
    - Pretty formatting
    """

    # Core SNMP Operations
    defdelegate get(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate get_next(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get_next(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate set(target, oid, value), to: SnmpKit.SnmpMgr
    defdelegate set(target, oid, value, opts), to: SnmpKit.SnmpMgr

    # Async Operations
    defdelegate get_async(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get_async(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate get_bulk_async(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get_bulk_async(target, oid, opts), to: SnmpKit.SnmpMgr

    # Bulk Operations
    defdelegate get_bulk(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get_bulk(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate bulk_walk(target, oid), to: SnmpKit.SnmpMgr
    defdelegate bulk_walk(target, oid, opts), to: SnmpKit.SnmpMgr

    @doc """
    Like get_bulk/3 but raises on error.
    """
    @spec get_bulk!(term(), term(), keyword()) :: term()
    def get_bulk!(target, oid, opts \\ []) do
      case get_bulk(target, oid, opts) do
        {:ok, result} -> result
        {:error, reason} -> raise("get_bulk! failed: #{inspect(reason)}")
      end
    end

    @doc """
    Like bulk_walk/3 but raises on error.
    """
    @spec bulk_walk!(term(), term(), keyword()) :: term()
    def bulk_walk!(target, root_oid, opts \\ []) do
      case bulk_walk(target, root_oid, opts) do
        {:ok, result} -> result
        {:error, reason} -> raise("bulk_walk! failed: #{inspect(reason)}")
      end
    end

    # Walk Operations
    defdelegate walk(target, oid), to: SnmpKit.SnmpMgr
    defdelegate walk(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate walk_table(target, table_oid), to: SnmpKit.SnmpMgr
    defdelegate walk_table(target, table_oid, opts), to: SnmpKit.SnmpMgr

    # Table Operations
    defdelegate get_column(target, table_oid, column), to: SnmpKit.SnmpMgr
    defdelegate get_column(target, table_oid, column, opts), to: SnmpKit.SnmpMgr

    # Pretty Formatting
    defdelegate get_pretty(target, oid), to: SnmpKit.SnmpMgr
    defdelegate get_pretty(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate walk_pretty(target, oid), to: SnmpKit.SnmpMgr
    defdelegate walk_pretty(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate bulk_pretty(target, oid), to: SnmpKit.SnmpMgr
    defdelegate bulk_pretty(target, oid, opts), to: SnmpKit.SnmpMgr
    defdelegate bulk_walk_pretty(target, oid), to: SnmpKit.SnmpMgr
    defdelegate bulk_walk_pretty(target, oid, opts), to: SnmpKit.SnmpMgr
  end

  defmodule MIB do
    @moduledoc """
    MIB (Management Information Base) operations.

    This module provides comprehensive MIB support including:
    - MIB compilation from source files
    - Loading and managing compiled MIBs
    - OID name resolution and reverse lookup
    - MIB tree navigation and analysis
    """
    alias SnmpKit.SnmpMgr.MIB

    # MIB Resolution and Lookup
    defdelegate resolve(name), to: MIB
    defdelegate reverse_lookup(oid), to: MIB
    defdelegate children(oid), to: MIB
    defdelegate parent(oid), to: MIB
    defdelegate walk_tree(root_oid), to: MIB
    defdelegate walk_tree(root_oid, opts), to: MIB

    # High-level MIB Management (SnmpMgr.MIB)
    defdelegate compile(mib_file), to: MIB
    defdelegate compile(mib_file, opts), to: MIB
    defdelegate compile_dir(directory), to: MIB
    defdelegate compile_dir(directory, opts), to: MIB
    defdelegate load(compiled_mib_path), to: MIB
    defdelegate parse_mib_file(mib_file), to: MIB
    defdelegate parse_mib_file(mib_file, opts), to: MIB
    defdelegate parse_mib_content(content), to: MIB
    defdelegate parse_mib_content(content, opts), to: MIB
    defdelegate resolve_enhanced(name), to: MIB
    defdelegate resolve_enhanced(name, opts), to: MIB
    defdelegate load_and_integrate_mib(mib_file), to: MIB
    defdelegate load_and_integrate_mib(mib_file, opts), to: MIB
    defdelegate load_standard_mibs(), to: MIB

    # Low-level MIB Compilation (SnmpLib.MIB)
    defdelegate compile_raw(mib_source), to: SnmpKit.SnmpLib.MIB, as: :compile
    defdelegate compile_raw(mib_source, opts), to: SnmpKit.SnmpLib.MIB, as: :compile
    defdelegate compile_string(mib_content), to: SnmpKit.SnmpLib.MIB
    defdelegate compile_string(mib_content, opts), to: SnmpKit.SnmpLib.MIB
    defdelegate load_compiled(compiled_path), to: SnmpKit.SnmpLib.MIB
    defdelegate compile_all(mib_files), to: SnmpKit.SnmpLib.MIB
    defdelegate compile_all(mib_files, opts), to: SnmpKit.SnmpLib.MIB

    # Registry Management
    defdelegate start_link(), to: MIB
    defdelegate start_link(opts), to: MIB
  end
end
