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

  import Mox

  alias Towerops.Snmp.Profiles.Vendors.Teltonika
  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 teltonika profile names" do
      assert Teltonika.profile_names() == ["rutos-rutx", "rutos-rutm"]
    end
  end

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

      assert Teltonika.detect_hardware(@client_opts) == "RUTX11"
    end

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

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

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

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

    test "includes RSSI sensor" do
      defs = Teltonika.wireless_oid_defs()
      rssi = Enum.find(defs, &(&1.sensor_descr == "Mobile Signal (RSSI)"))

      assert rssi
      assert rssi.sensor_type == "rssi"
      assert rssi.sensor_unit == "dBm"
    end

    test "includes RSRP sensor" do
      defs = Teltonika.wireless_oid_defs()
      rsrp = Enum.find(defs, &(&1.sensor_descr == "RSRP"))

      assert rsrp
      assert rsrp.sensor_type == "rssi"
    end

    test "includes SINR sensor" do
      defs = Teltonika.wireless_oid_defs()
      sinr = Enum.find(defs, &(&1.sensor_descr == "SINR"))

      assert sinr
      assert sinr.sensor_type == "snr"
      assert sinr.sensor_unit == "dB"
    end

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

      assert temp
      assert temp.sensor_descr == "Device Temperature"
      assert temp.sensor_divisor == 10
    end
  end

  describe "discover_wireless_sensors/1" do
    test "discovers sensors when SNMP responds" do
      # Note: fetch_sensor_value only accepts integer values, so state sensors
      # (Connection Type, SIM Status, Network Operator) that return strings won't be collected
      expect(SnmpMock, :get, 8, fn _, oid, _ ->
        cond do
          String.contains?(oid, "48690.2.2.1.7.1") -> {:ok, -65}
          String.contains?(oid, "48690.2.2.1.8.1") -> {:ok, -85}
          String.contains?(oid, "48690.2.2.1.10.1") -> {:ok, -10}
          String.contains?(oid, "48690.2.2.1.9.1") -> {:ok, 15}
          String.contains?(oid, "48690.2.2.1.3.1") -> {:ok, "LTE"}
          String.contains?(oid, "48690.2.2.1.2.1") -> {:ok, "inserted"}
          String.contains?(oid, "48690.2.2.1.4.1") -> {:ok, "T-Mobile"}
          String.contains?(oid, "48690.1.7.0") -> {:ok, 450}
          true -> {:error, :no_such_object}
        end
      end)

      sensors = Teltonika.discover_wireless_sensors(@client_opts)

      assert is_list(sensors)
      # Only 5 sensors: RSSI, RSRP, RSRQ, SINR, and Temperature (the numeric ones)
      assert length(sensors) == 5
    end

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

      sensors = Teltonika.discover_wireless_sensors(@client_opts)

      assert sensors == []
    end
  end
end
