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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.Siklu
  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 siklu profile name" do
      assert Siklu.profile_names() == ["siklu"]
    end
  end

  describe "detect_hardware/1" do
    test "detects EtherHaul model from software bank 1 version when running" do
      # First checks if bank 1 is running
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.2.0", _ ->
        {:ok, {:octet_string, "running"}}
      end)

      # Then gets bank 1 version
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.3.0", _ ->
        {:ok, {:octet_string, "EH-1200F v9.0.1"}}
      end)

      assert Siklu.detect_hardware(@client_opts) == "EH-1200F v9.0.1"
    end

    test "falls back to bank 2 version when bank 1 not running" do
      # Bank 1 is not running
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.2.0", _ ->
        {:ok, {:octet_string, "not_running"}}
      end)

      # Gets bank 2 version
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.5.0", _ ->
        {:ok, {:octet_string, "EH-600T v8.5.0"}}
      end)

      assert Siklu.detect_hardware(@client_opts) == "EH-600T v8.5.0"
    end

    test "returns nil when OIDs unavailable" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.2.0", _ ->
        {:error, :no_such_object}
      end)

      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.31926.1.1.1.5.0", _ ->
        {:error, :no_such_object}
      end)

      assert Siklu.detect_hardware(@client_opts) == nil
    end
  end

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

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

    test "includes frequency sensor" do
      defs = Siklu.wireless_oid_defs()
      freq = Enum.find(defs, &(&1.sensor_type == "frequency"))

      assert freq
      assert freq.sensor_unit == "MHz"
    end

    test "includes power sensor" do
      defs = Siklu.wireless_oid_defs()
      power = Enum.find(defs, &(&1.sensor_type == "power"))

      assert power
      assert power.sensor_descr == "Tx Power"
    end

    test "includes RSSI sensor" do
      defs = Siklu.wireless_oid_defs()
      rssi = Enum.find(defs, &(&1.sensor_type == "rssi"))

      assert rssi
      assert rssi.sensor_unit == "dBm"
    end

    test "includes CINR sensor" do
      defs = Siklu.wireless_oid_defs()
      cinr = Enum.find(defs, &(&1.sensor_descr == "CINR"))

      assert cinr
      assert cinr.sensor_type == "snr"
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      expect(SnmpMock, :get, 4, fn _, oid, _ ->
        cond do
          # Frequency OID
          String.contains?(oid, "31926.2.1.1.4.1") -> {:ok, {:integer, 71_000}}
          # Tx Power OID
          String.contains?(oid, "31926.2.1.1.42.1") -> {:ok, {:integer, 18}}
          # RSSI OID
          String.contains?(oid, "31926.2.1.1.19.1") -> {:ok, {:integer, -45}}
          # CINR (SNR) OID
          String.contains?(oid, "31926.2.1.1.18.1") -> {:ok, {:integer, 25}}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Siklu.discover_wireless_sensors(@client_opts)

      assert is_list(sensors)
      assert length(sensors) == 4
    end

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

      sensors = Siklu.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
