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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.Airfiber
  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 airfiber profile names" do
      assert Airfiber.profile_names() == ["airos-af", "airos-af-ltu", "airos-af60"]
    end
  end

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

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

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

    test "includes frequency sensors" do
      defs = Airfiber.wireless_oid_defs()
      freq_sensors = Enum.filter(defs, &(&1.sensor_type == "frequency"))

      assert length(freq_sensors) == 2
      assert Enum.all?(freq_sensors, &(&1.sensor_unit == "MHz"))
    end

    test "includes RSSI sensors" do
      defs = Airfiber.wireless_oid_defs()
      rssi_sensors = Enum.filter(defs, &(&1.sensor_type == "rssi"))

      assert length(rssi_sensors) == 2
    end

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

      assert length(rate_sensors) == 2
      assert Enum.all?(rate_sensors, &(&1.sensor_unit == "Mbps"))
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors from regular AirFiber device" do
      # First call checks for LTU device (returns error = not LTU)
      # Then 7 calls for regular AirFiber sensors
      expect(SnmpMock, :get, 8, fn _target, oid, _opts ->
        cond do
          # LTU detection OID (should fail for regular AirFiber)
          String.contains?(oid, "41112.1.10.1.2.2.0") -> {:error, :no_such_object}
          # Regular AirFiber OIDs (should succeed)
          String.contains?(oid, "41112.1.3.2.1.6.1") -> {:ok, 5800}
          String.contains?(oid, "41112.1.3.2.1.7.1") -> {:ok, 5800}
          String.contains?(oid, "41112.1.3.2.1.8.1") -> {:ok, 25}
          String.contains?(oid, "41112.1.3.2.1.13.1") -> {:ok, -55}
          String.contains?(oid, "41112.1.3.2.1.14.1") -> {:ok, -56}
          String.contains?(oid, "41112.1.3.2.1.20.1") -> {:ok, 450}
          String.contains?(oid, "41112.1.3.2.1.21.1") -> {:ok, 450}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Airfiber.discover_wireless_sensors(@client_opts)

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

      # Verify regular AirFiber OIDs were used
      freq_sensors = Enum.filter(sensors, &(&1.sensor_type == "frequency"))
      assert length(freq_sensors) == 2
    end

    test "discovers sensors from LTU device with correct OIDs" do
      # First call detects LTU device (returns frequency)
      # Then 6 calls for LTU-specific sensors
      expect(SnmpMock, :get, 7, fn _target, oid, _opts ->
        cond do
          # LTU detection OID (should succeed for LTU)
          String.contains?(oid, "41112.1.10.1.2.2.0") -> {:ok, 5800}
          # LTU-specific OIDs
          String.contains?(oid, "41112.1.10.1.2.6.0") -> {:ok, 25}
          String.contains?(oid, "41112.1.10.1.4.1.5.1") -> {:ok, -55}
          String.contains?(oid, "41112.1.10.1.4.1.6.1") -> {:ok, -56}
          String.contains?(oid, "41112.1.10.1.4.1.3.1") -> {:ok, 450_000}
          String.contains?(oid, "41112.1.10.1.4.1.4.1") -> {:ok, 450_000}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Airfiber.discover_wireless_sensors(@client_opts)

      assert is_list(sensors)
      assert length(sensors) == 6

      # Verify LTU OIDs were used
      rate_sensors = Enum.filter(sensors, &(&1.sensor_type == "rate"))
      assert length(rate_sensors) == 2
      # Verify the divisor is set correctly (division happens at display time)
      assert Enum.all?(rate_sensors, &(&1.sensor_divisor == 1000))
      # Raw value should be 450000 Kbps (not divided during discovery)
      assert Enum.all?(rate_sensors, &(&1.last_value == 450_000.0))
    end

    test "returns empty list when LTU device has no active stations" do
      # LTU detected but no station data available
      expect(SnmpMock, :get, 7, fn _target, oid, _opts ->
        # LTU detection succeeds
        if String.contains?(oid, "41112.1.10.1.2.2.0") do
          {:ok, 5800}
        else
          # But station OIDs fail (no connected stations)
          {:error, :no_such_object}
        end
      end)

      sensors = Airfiber.discover_wireless_sensors(@client_opts)

      # Frequency sensor should still be discovered
      assert is_list(sensors)
      assert length(sensors) == 1
      assert List.first(sensors).sensor_type == "frequency"
    end

    test "returns empty list when device does not respond" do
      expect(SnmpMock, :get, 8, fn _target, _oid, _opts ->
        {:error, :timeout}
      end)

      sensors = Airfiber.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
