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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.CambiumPtp
  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 all PTP profile names" do
      profiles = CambiumPtp.profile_names()

      assert "ptp650" in profiles
      assert "ptp670" in profiles
      assert "ptp450" in profiles
      assert "ptp550" in profiles
      assert "ptp800" in profiles
    end
  end

  describe "detect_hardware/1" do
    test "detects hardware from model OID" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.4.1.17713.7.1.1.0", _ ->
        {:ok, "PTP 670"}
      end)

      assert CambiumPtp.detect_hardware(@client_opts) == "PTP 670"
    end

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

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

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

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

    test "includes receive power (RSL) sensor" do
      defs = CambiumPtp.wireless_oid_defs()
      rsl = Enum.find(defs, &(&1.sensor_descr == "Receive Power"))

      assert rsl
      assert rsl.sensor_type == "rssi"
      assert rsl.sensor_unit == "dBm"
      assert rsl.sensor_divisor == 10
    end

    test "includes transmit power sensor" do
      defs = CambiumPtp.wireless_oid_defs()
      tx = Enum.find(defs, &(&1.sensor_descr == "Transmit Power"))

      assert tx
      assert tx.sensor_type == "power"
      assert tx.sensor_divisor == 10
    end

    test "includes vector error sensor" do
      defs = CambiumPtp.wireless_oid_defs()
      ve = Enum.find(defs, &(&1.sensor_descr == "Vector Error"))

      assert ve
      assert ve.sensor_type == "snr"
    end

    test "includes data rate sensors" do
      defs = CambiumPtp.wireless_oid_defs()
      rx_rate = Enum.find(defs, &(&1.sensor_descr == "Rx Data Rate"))
      tx_rate = Enum.find(defs, &(&1.sensor_descr == "Tx Data Rate"))

      assert rx_rate
      assert rx_rate.sensor_type == "capacity"
      assert tx_rate
      assert tx_rate.sensor_type == "capacity"
    end

    test "includes temperature sensor" do
      defs = CambiumPtp.wireless_oid_defs()
      temp = Enum.find(defs, &(&1.sensor_type == "temperature"))

      assert temp
      assert temp.sensor_descr == "Radio Temperature"
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      expect(SnmpMock, :get, 7, fn _, oid, _ ->
        cond do
          String.contains?(oid, "17713.7.12.6.0") -> {:ok, -550}
          String.contains?(oid, "17713.7.12.3.0") -> {:ok, 230}
          String.contains?(oid, "17713.7.12.8.0") -> {:ok, 350}
          String.contains?(oid, "17713.7.12.9.0") -> {:ok, 15}
          String.contains?(oid, "17713.7.12.14.0") -> {:ok, 350_000}
          String.contains?(oid, "17713.7.12.15.0") -> {:ok, 350_000}
          String.contains?(oid, "17713.7.13.1.0") -> {:ok, 42}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = CambiumPtp.discover_wireless_sensors(@client_opts)

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

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

      sensors = CambiumPtp.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
