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

  import Mox

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

  describe "detect_hardware/1" do
    test "extracts hardware model from sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "EdgeSwitch 24-250W, firmware 1.9.1.5274897, Linux 4.4.153"}
      end)

      assert Edgeswitch.detect_hardware(@client_opts) == "EdgeSwitch 24-250W"
    end

    test "handles EdgePoint Switch sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "EdgePoint Switch ES-8XP, firmware 1.7.3.4969649, Linux 3.6.5"}
      end)

      assert Edgeswitch.detect_hardware(@client_opts) == "EdgePoint Switch ES-8XP"
    end

    test "handles USW series sysDescr" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:ok, "USW-48-PoE, firmware 5.43.35.12724, Linux 4.9.147"}
      end)

      assert Edgeswitch.detect_hardware(@client_opts) == "USW-48-PoE"
    end

    test "returns nil when sysDescr is not available" do
      expect(SnmpMock, :get, fn _, "1.3.6.1.2.1.1.1.0", _ ->
        {:error, :no_such_object}
      end)

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

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

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

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

      assert temp
      assert temp.sensor_descr == "Temperature"
      assert temp.sensor_unit == "C"
    end

    test "includes fan speed sensor" do
      defs = Edgeswitch.wireless_oid_defs()
      fan = Enum.find(defs, &(&1.sensor_type == "fanspeed"))

      assert fan
      assert fan.sensor_descr == "Fan"
      assert fan.sensor_unit == "RPM"
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers temperature sensors" do
      expect(SnmpMock, :walk, 5, fn _, oid, _ ->
        cond do
          # Temperature sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.5" ->
            {:ok,
             [
               %{oid: "1.3.6.1.4.1.4413.1.1.43.1.8.1.5.1", value: 45},
               %{oid: "1.3.6.1.4.1.4413.1.1.43.1.8.1.5.2", value: 42}
             ]}

          # Fan speed sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.4" ->
            {:ok, []}

          # Chassis state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.15.1.2" ->
            {:ok, []}

          # Temp sensor state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.4" ->
            {:ok, []}

          # Fan state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.3" ->
            {:ok, []}

          true ->
            {:ok, []}
        end
      end)

      sensors = Edgeswitch.discover_wireless_sensors(@client_opts)

      temp_sensors = Enum.filter(sensors, &(&1.sensor_type == "temperature"))
      assert length(temp_sensors) == 2

      sensor1 = Enum.find(temp_sensors, &(&1.sensor_index == "edgeswitch_temp_1"))
      assert sensor1.sensor_descr == "Temperature 1"
      assert sensor1.last_value == 45
    end

    test "discovers fan speed sensors" do
      expect(SnmpMock, :walk, 5, fn _, oid, _ ->
        cond do
          # Temperature sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.5" ->
            {:ok, []}

          # Fan speed sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.4" ->
            {:ok, [%{oid: "1.3.6.1.4.1.4413.1.1.43.1.6.1.4.1", value: 3500}]}

          # Chassis state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.15.1.2" ->
            {:ok, []}

          # Temp sensor state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.4" ->
            {:ok, []}

          # Fan state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.3" ->
            {:ok, []}

          true ->
            {:ok, []}
        end
      end)

      sensors = Edgeswitch.discover_wireless_sensors(@client_opts)

      fan_sensors = Enum.filter(sensors, &(&1.sensor_type == "fanspeed"))
      assert length(fan_sensors) == 1

      sensor = hd(fan_sensors)
      assert sensor.sensor_descr == "Fan 1"
      assert sensor.sensor_unit == "RPM"
      assert sensor.last_value == 3500
    end

    test "discovers state sensors" do
      expect(SnmpMock, :walk, 5, fn _, oid, _ ->
        cond do
          # Temperature sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.5" ->
            {:ok, []}

          # Fan speed sensors
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.4" ->
            {:ok, []}

          # Chassis state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.15.1.2" ->
            {:ok, [%{oid: "1.3.6.1.4.1.4413.1.1.43.1.15.1.2.1", value: 1}]}

          # Temp sensor state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.8.1.4" ->
            {:ok, [%{oid: "1.3.6.1.4.1.4413.1.1.43.1.8.1.4.1", value: 1}]}

          # Fan state
          oid == "1.3.6.1.4.1.4413.1.1.43.1.6.1.3" ->
            {:ok, [%{oid: "1.3.6.1.4.1.4413.1.1.43.1.6.1.3.1", value: 2}]}

          true ->
            {:ok, []}
        end
      end)

      sensors = Edgeswitch.discover_wireless_sensors(@client_opts)

      state_sensors = Enum.filter(sensors, &(&1.sensor_type == "state"))
      assert length(state_sensors) == 3

      chassis = Enum.find(state_sensors, &(&1.sensor_descr == "Chassis state"))
      assert chassis
      assert chassis.last_value == 1

      temp_state = Enum.find(state_sensors, &(&1.sensor_descr == "Temp Sensor 1"))
      assert temp_state
      assert temp_state.last_value == 1

      fan_state = Enum.find(state_sensors, &(&1.sensor_descr == "Fan 1"))
      assert fan_state
      assert fan_state.last_value == 2
    end

    test "returns empty list when no sensors respond" do
      expect(SnmpMock, :walk, 5, fn _, _, _ ->
        {:ok, []}
      end)

      sensors = Edgeswitch.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
