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

  import Mox

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

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

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

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

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

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

    test "includes noise floor sensor" do
      defs = Ligoos.wireless_oid_defs()
      noise = Enum.find(defs, &(&1.sensor_type == "noise-floor"))

      assert noise
      assert noise.sensor_unit == "dBm"
    end

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

      assert quality
      assert quality.sensor_unit == "%"
    end

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

      assert clients
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers scalar sensors when SNMP responds" do
      # Mock scalar sensors
      expect(SnmpMock, :get, 4, fn _, oid, _ ->
        cond do
          String.contains?(oid, "32750.3.10.1.2.1.1.6.1") -> {:ok, {:integer, 5800}}
          String.contains?(oid, "32750.3.10.1.2.1.1.15.1") -> {:ok, {:integer, -95}}
          String.contains?(oid, "32750.3.10.1.2.1.1.12.1") -> {:ok, {:integer, 85}}
          String.contains?(oid, "32750.3.10.1.2.1.1.16.1") -> {:ok, {:integer, 10}}
          true -> {:error, :no_such_object}
        end
      end)

      # Mock table walk for per-interface clients
      expect(SnmpMock, :walk, fn _, "1.3.6.1.4.1.32750.3.10.1.2.1.1.16", _ ->
        {:ok, []}
      end)

      sensors = Ligoos.discover_wireless_sensors(@client_opts)

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

    test "discovers table sensors for multiple interfaces" do
      # Mock scalar sensors
      expect(SnmpMock, :get, 4, fn _, _, _ ->
        {:error, :no_such_object}
      end)

      # Mock table walk with multiple interfaces - values are raw (extracted by Client)
      expect(SnmpMock, :walk, fn _, "1.3.6.1.4.1.32750.3.10.1.2.1.1.16", _ ->
        {:ok,
         [
           %{oid: "1.3.6.1.4.1.32750.3.10.1.2.1.1.16.1", value: 15},
           %{oid: "1.3.6.1.4.1.32750.3.10.1.2.1.1.16.2", value: 8}
         ]}
      end)

      sensors = Ligoos.discover_wireless_sensors(@client_opts)

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

      # Check interface-specific sensors
      if1 = Enum.find(sensors, &(&1.sensor_index == "ligoos_clients_1"))
      assert if1
      assert if1.last_value == 15.0

      if2 = Enum.find(sensors, &(&1.sensor_index == "ligoos_clients_2"))
      assert if2
      assert if2.last_value == 8.0
    end

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

      expect(SnmpMock, :walk, fn _, _, _ ->
        {:ok, []}
      end)

      sensors = Ligoos.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
