defmodule Towerops.Snmp.Profiles.Vendors.SafTest do
  use Towerops.DataCase, async: true

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.Saf
  alias Towerops.Snmp.SnmpMock

  setup :verify_on_exit!

  @client_opts [
    ip: "192.168.1.1",
    community: "public",
    version: "2c",
    port: 161,
    timeout: 5000
  ]

  describe "profile_names/0" do
    test "returns saf profile name" do
      assert Saf.profile_names() == ["saf"]
    end
  end

  describe "detect_hardware/1" do
    test "returns nil (hardware detection handled by YAML)" do
      assert Saf.detect_hardware(@client_opts) == nil
    end
  end

  describe "wireless_oid_defs/0" do
    test "returns list of wireless sensor definitions" do
      defs = Saf.wireless_oid_defs()

      assert is_list(defs)
      assert [_ | _] = defs
    end

    test "includes frequency sensors with correct divisor" do
      defs = Saf.wireless_oid_defs()
      freq_sensors = Enum.filter(defs, &(&1.sensor_type == "frequency"))

      assert length(freq_sensors) == 2
      # SAF frequency is in kHz, divide by 1000 for MHz
      assert Enum.all?(freq_sensors, &(&1.sensor_divisor == 1000))
    end

    test "includes MSE sensor with correct divisor" do
      defs = Saf.wireless_oid_defs()
      mse = Enum.find(defs, &(&1.sensor_type == "mse"))

      assert mse
      assert mse.sensor_descr == "Radial MSE"
      # MSE is divided by 10
      assert mse.sensor_divisor == 10
    end

    test "includes power sensors" do
      defs = Saf.wireless_oid_defs()
      power_sensors = Enum.filter(defs, &(&1.sensor_type == "power"))

      assert length(power_sensors) == 2
      # Rx and Tx power
      assert Enum.any?(power_sensors, &String.contains?(&1.sensor_descr, "Rx"))
      assert Enum.any?(power_sensors, &String.contains?(&1.sensor_descr, "Tx"))
    end

    test "includes rate sensors" do
      defs = Saf.wireless_oid_defs()
      rate_sensors = Enum.filter(defs, &(&1.sensor_type == "rate"))

      assert length(rate_sensors) == 2
      # ACM and Total capacity
      assert Enum.any?(rate_sensors, &String.contains?(&1.sensor_descr, "ACM"))
      assert Enum.any?(rate_sensors, &String.contains?(&1.sensor_descr, "Total"))
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      expect(SnmpMock, :get, 7, fn _, oid, _ ->
        cond do
          String.contains?(oid, "7571.100.1.1.5.1.1.1.10.1.9.1") -> {:ok, {:integer, 71_000_000}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.10.1.10.1") -> {:ok, {:integer, 81_000_000}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.12.1.10.1") -> {:ok, {:integer, -150}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.10.1.5.1") -> {:ok, {:integer, -45}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.10.1.4.1") -> {:ok, {:integer, 20}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.12.1.18.1") -> {:ok, {:integer, 500_000}}
          String.contains?(oid, "7571.100.1.1.5.1.1.1.12.1.6.1") -> {:ok, {:integer, 1_000_000}}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Saf.discover_wireless_sensors(@client_opts)

      assert is_list(sensors)
      assert length(sensors) == 7

      # Check Tx frequency
      tx_freq = Enum.find(sensors, &(&1.sensor_descr == "Tx Frequency"))
      assert tx_freq
      assert tx_freq.last_value == 71_000_000.0
    end

    test "returns empty list when no sensors respond" do
      expect(SnmpMock, :get, 7, fn _, _, _ ->
        {:error, :no_such_object}
      end)

      sensors = Saf.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
