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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.Meraki
  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 meraki profile names" do
      assert Meraki.profile_names() == ["merakimr", "merakims", "merakimx"]
    end
  end

  describe "detect_hardware/1" do
    test "detects MR series AP from sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Meraki MR46 Cloud Managed AP"}
      end)

      assert Meraki.detect_hardware(@client_opts) == "MR46"
    end

    test "detects CW series AP from sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Meraki CW9166 Cloud Managed AP"}
      end)

      assert Meraki.detect_hardware(@client_opts) == "CW9166"
    end

    test "detects MS series switch from sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Meraki MS350-24X Cloud Managed Switch"}
      end)

      assert Meraki.detect_hardware(@client_opts) == "MS350"
    end

    test "detects MX series appliance from sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "Meraki MX84 Cloud Managed Security Appliance"}
      end)

      assert Meraki.detect_hardware(@client_opts) == "MX84"
    end

    test "returns nil for non-Meraki device" do
      expect(SnmpMock, :get, fn _, _, _ ->
        {:ok, "Some Other Device"}
      end)

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

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

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

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

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

    test "includes radio channel sensors" do
      defs = Meraki.wireless_oid_defs()
      radio1 = Enum.find(defs, &(&1.sensor_descr == "Radio 1 Channel"))
      radio2 = Enum.find(defs, &(&1.sensor_descr == "Radio 2 Channel"))

      assert radio1
      assert radio1.sensor_type == "frequency"
      assert radio2
      assert radio2.sensor_type == "frequency"
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      expect(SnmpMock, :get, 2, fn _, oid, _ ->
        cond do
          String.contains?(oid, "10036.4.5.1.1.1") -> {:ok, 36}
          String.contains?(oid, "10036.4.5.1.1.2") -> {:ok, 149}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Meraki.discover_wireless_sensors(@client_opts)

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

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

      sensors = Meraki.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
