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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.AlliedTelesis
  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 Allied Telesis profile names" do
      assert AlliedTelesis.profile_names() == ["allied", "awplus", "allied-tq", "radlan"]
    end
  end

  describe "detect_hardware/1" do
    test "returns model when AT- prefix found in sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Allied Telesis AT-x530-28GTXm switch"}
      end)

      assert AlliedTelesis.detect_hardware(@client_opts) == "AT-x530-28GTXm"
    end

    test "returns model when x-series found in sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Allied Telesis x310-26FT switch"}
      end)

      assert AlliedTelesis.detect_hardware(@client_opts) == "x310-26FT"
    end

    test "returns AlliedWare Plus when found in sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "AlliedWare Plus software version 5.4.9"}
      end)

      assert AlliedTelesis.detect_hardware(@client_opts) == "AlliedWare Plus"
    end

    test "returns nil when model not in sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Some other device"}
      end)

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

    test "returns nil when SNMP fails" do
      expect(SnmpMock, :get, fn _, _, _ ->
        {:error, :timeout}
      end)

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

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

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

    test "includes CPU 5min average sensor" do
      defs = AlliedTelesis.wireless_oid_defs()
      cpu = Enum.find(defs, &(&1.sensor_descr == "CPU 5min Average"))

      assert cpu
      assert cpu.sensor_type == "load"
      assert cpu.sensor_unit == "%"
    end

    test "includes temperature sensor" do
      defs = AlliedTelesis.wireless_oid_defs()
      temp = Enum.find(defs, &(&1.sensor_descr == "Temperature"))

      assert temp
      assert temp.sensor_type == "temperature"
      assert temp.sensor_unit == "°C"
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      expect(SnmpMock, :get, 5, fn _, oid, _ ->
        cond do
          String.contains?(oid, "207.8.4.4.3.3.7.0") -> {:ok, 15}
          String.contains?(oid, "207.8.4.4.3.7.1.0") -> {:ok, 1_024_000}
          String.contains?(oid, "207.8.4.4.3.12.3.1.5.1") -> {:ok, 42}
          String.contains?(oid, "207.8.4.4.3.12.1.1.5.1") -> {:ok, 3500}
          String.contains?(oid, "1.3.0") -> {:ok, 987_654_321}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = AlliedTelesis.discover_wireless_sensors(@client_opts)

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

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

      sensors = AlliedTelesis.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
