defmodule Towerops.Snmp.Profiles.Vendors.Airos do
  @moduledoc """
  Ubiquiti AirOS device-specific SNMP handling.

  Mirrors LibreNMS/OS/Airos.php for wireless sensor discovery and hardware detection.

  Supported devices:
  - AirMax (LiteBeam, PowerBeam, NanoStation, etc.)
  """

  @behaviour Towerops.Snmp.Profiles.Vendors.Vendor

  alias Towerops.Snmp.Client
  alias Towerops.Snmp.Profiles.Vendors.Vendor

  require Logger

  # OIDs for hardware detection
  # Use get_next like LibreNMS to get the first available value in the IEEE802dot11-MIB tree
  # IEEE802dot11-MIB::dot11manufacturerProductName = 1.2.840.10036.3.1.2.1.3
  # IEEE802dot11-MIB::dot11manufacturerProductVersion = 1.2.840.10036.3.1.2.1.4
  @product_name_oid "1.2.840.10036.3.1.2.1.3"
  @product_version_oid "1.2.840.10036.3.1.2.1.4"

  @impl true
  def profile_names, do: ["airos"]

  @impl true
  def detect_hardware(client_opts) do
    # Use get_next like LibreNMS does - this gets the first available instance
    # Works even when .0 index doesn't exist
    Logger.info("AirOS: Attempting to detect hardware using GET-NEXT on #{@product_name_oid}")

    result = Client.get_next(client_opts, @product_name_oid)
    Logger.info("AirOS: GET-NEXT result: #{inspect(result)}")

    case result do
      {:ok, %{value: product_name}} when is_binary(product_name) and product_name != "" ->
        Logger.info("AirOS: Detected hardware: #{product_name}")
        product_name

      other ->
        Logger.warning("AirOS: Failed to detect hardware, got: #{inspect(other)}")
        # If get_next fails, return nil (will fallback to sysDescr in Dynamic module)
        nil
    end
  end

  @doc """
  Get firmware version from IEEE802dot11-MIB using get_next.
  Returns version string with .v prefix removed (e.g., "8.7.21.48401.251212.0939").
  """
  def detect_version(client_opts) do
    Logger.info("AirOS: Attempting to detect version using GET-NEXT on #{@product_version_oid}")

    result = Client.get_next(client_opts, @product_version_oid)
    Logger.info("AirOS: GET-NEXT result: #{inspect(result)}")

    case result do
      {:ok, %{value: version}} when is_binary(version) and version != "" ->
        # Extract version from format like "XW.v8.7.21.48401.251212.0939"
        # Remove the ".v" prefix to get just "8.7.21.48401.251212.0939"
        extracted =
          case Regex.run(~r/\.v(.*)$/, version) do
            [_, extracted_version] -> extracted_version
            _ -> version
          end

        Logger.info("AirOS: Detected version: #{extracted} (raw: #{version})")
        extracted

      other ->
        Logger.warning("AirOS: Failed to detect version, got: #{inspect(other)}")
        nil
    end
  end

  @impl true
  def discover_wireless_sensors(client_opts) do
    Vendor.fetch_sensors(wireless_oid_defs(), client_opts)
  end

  @impl true
  def wireless_oid_defs do
    [
      # Frequency in MHz
      %{
        oid: "1.3.6.1.4.1.41112.1.4.1.1.4.1",
        sensor_type: "frequency",
        sensor_descr: "Frequency",
        sensor_unit: "MHz",
        sensor_divisor: 1
      },
      # Capacity in Mbps
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.9.1",
        sensor_type: "rate",
        sensor_descr: "Capacity",
        sensor_unit: "Mbps",
        sensor_divisor: 1
      },
      # CCQ (Client Connection Quality) %
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.7.1",
        sensor_type: "ccq",
        sensor_descr: "CCQ",
        sensor_unit: "%",
        sensor_divisor: 1
      },
      # Connected clients
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.15.1",
        sensor_type: "clients",
        sensor_descr: "Clients",
        sensor_unit: "",
        sensor_divisor: 1
      },
      # Distance in meters
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.11.1",
        sensor_type: "distance",
        sensor_descr: "Distance",
        sensor_unit: "m",
        sensor_divisor: 1
      },
      # Noise floor in dBm
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.8.1",
        sensor_type: "noise-floor",
        sensor_descr: "Noise Floor",
        sensor_unit: "dBm",
        sensor_divisor: 1
      },
      # Tx Power in dBm
      %{
        oid: "1.3.6.1.4.1.41112.1.4.1.1.6.1",
        sensor_type: "power",
        sensor_descr: "Tx Power",
        sensor_unit: "dBm",
        sensor_divisor: 1
      },
      # Signal Quality %
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.5.1",
        sensor_type: "quality",
        sensor_descr: "Signal Quality",
        sensor_unit: "%",
        sensor_divisor: 1
      },
      # Tx Rate in Mbps
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.2.1",
        sensor_type: "rate",
        sensor_descr: "Tx Rate",
        sensor_unit: "Mbps",
        sensor_divisor: 1
      },
      # Rx Rate in Mbps
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.3.1",
        sensor_type: "rate",
        sensor_descr: "Rx Rate",
        sensor_unit: "Mbps",
        sensor_divisor: 1
      },
      # RSSI in dBm
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.5.1",
        sensor_type: "rssi",
        sensor_descr: "RSSI",
        sensor_unit: "dBm",
        sensor_divisor: 1
      },
      # Channel utilization Tx %
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.12.1",
        sensor_type: "utilization",
        sensor_descr: "Channel Utilization Tx",
        sensor_unit: "%",
        sensor_divisor: 1
      },
      # Channel utilization Rx %
      %{
        oid: "1.3.6.1.4.1.41112.1.4.5.1.13.1",
        sensor_type: "utilization",
        sensor_descr: "Channel Utilization Rx",
        sensor_unit: "%",
        sensor_divisor: 1
      }
    ]
  end
end
