defmodule ToweropsNativeTest do
  use ExUnit.Case, async: false

  # Suppress false positive dialyzer warnings for NIF return types
  @dialyzer :no_match

  # NIF not compiled in this worktree — skip all tests
  @moduletag :skip

  setup do
    # Initialize MIB library (auto-initializes on first resolve_oid call anyway)
    result = ToweropsNative.init_mib_library()
    assert result in ["initialized", "already_initialized"]

    # Load MIBs before tests run
    mib_dir = Application.app_dir(:towerops, "priv/mibs")
    assert :ok = ToweropsNative.load_mib_directory(mib_dir)

    :ok
  end

  describe "init_mib_library/0" do
    test "initializes successfully and returns status" do
      # Should return "initialized" or "already_initialized"
      result = ToweropsNative.init_mib_library()
      assert result in ["initialized", "already_initialized"]
    end

    test "returns already_initialized on subsequent calls" do
      # First call
      ToweropsNative.init_mib_library()

      # Second call should return already_initialized
      result = ToweropsNative.init_mib_library()
      assert result == "already_initialized"
    end
  end

  describe "load_mib_directory/1" do
    test "returns ok for valid directory path" do
      mib_dir = Application.app_dir(:towerops, "priv/mibs")
      assert :ok = ToweropsNative.load_mib_directory(mib_dir)
    end

    test "handles paths with spaces" do
      # Create a temporary directory with spaces
      temp_dir = System.tmp_dir!()
      dir_with_spaces = Path.join(temp_dir, "test dir with spaces")
      File.mkdir_p!(dir_with_spaces)

      # Should not crash and return :ok
      assert :ok = ToweropsNative.load_mib_directory(dir_with_spaces)

      # Cleanup
      File.rm_rf!(dir_with_spaces)
    end
  end

  describe "resolve_oid/1" do
    test "resolves standard MIB names to exact OIDs" do
      # sysDescr = 1.3.6.1.2.1.1.1
      assert "1.3.6.1.2.1.1.1" = ToweropsNative.resolve_oid("sysDescr")

      # sysObjectID = 1.3.6.1.2.1.1.2
      assert "1.3.6.1.2.1.1.2" = ToweropsNative.resolve_oid("sysObjectID")

      # sysUpTime = 1.3.6.1.2.1.1.3
      assert "1.3.6.1.2.1.1.3" = ToweropsNative.resolve_oid("sysUpTime")

      # sysContact = 1.3.6.1.2.1.1.4
      assert "1.3.6.1.2.1.1.4" = ToweropsNative.resolve_oid("sysContact")

      # sysName = 1.3.6.1.2.1.1.5
      assert "1.3.6.1.2.1.1.5" = ToweropsNative.resolve_oid("sysName")

      # sysLocation = 1.3.6.1.2.1.1.6
      assert "1.3.6.1.2.1.1.6" = ToweropsNative.resolve_oid("sysLocation")
    end

    test "resolves vendor MIB names if available" do
      # IEEE802dot11-MIB::dot11manufacturerProductName
      # = 1.2.840.10036.3.1.2.1.3
      # Note: This MIB may not be available on all systems
      case ToweropsNative.resolve_oid("dot11manufacturerProductName") do
        oid when is_binary(oid) ->
          assert String.starts_with?(oid, "1.2.840.10036")

        {:error, _reason} ->
          # Vendor MIB not installed - that's OK, skip this test
          :ok
      end

      # IEEE802dot11-MIB::dot11manufacturerProductVersion
      # = 1.2.840.10036.3.1.2.1.4
      case ToweropsNative.resolve_oid("dot11manufacturerProductVersion") do
        oid when is_binary(oid) ->
          assert String.starts_with?(oid, "1.2.840.10036")

        {:error, _reason} ->
          # Vendor MIB not installed - that's OK, skip this test
          :ok
      end
    end

    test "handles MODULE::name format" do
      # net-snmp natively supports MODULE::name format
      oid1 = ToweropsNative.resolve_oid("SNMPv2-MIB::sysDescr")
      oid2 = ToweropsNative.resolve_oid("sysDescr")

      # Both should resolve to the same OID (dialyzer can't infer these always succeed)
      assert is_binary(oid1)
      assert is_binary(oid2)
      assert oid1 == oid2
      assert oid1 == "1.3.6.1.2.1.1.1"
    end

    test "returns error tuple for invalid MIB names" do
      assert {:error, reason} = ToweropsNative.resolve_oid("nonExistentMibName")
      assert is_binary(reason)

      assert {:error, reason} = ToweropsNative.resolve_oid("invalidMibObject123")
      assert is_binary(reason)
    end

    test "handles empty strings" do
      assert {:error, reason} = ToweropsNative.resolve_oid("")
      assert is_binary(reason)
    end

    test "performance is fast after initial load" do
      # Warm up cache with first call
      ToweropsNative.resolve_oid("sysDescr")

      # Measure 100 resolutions
      {time_microseconds, _result} =
        :timer.tc(fn ->
          for _ <- 1..100 do
            ToweropsNative.resolve_oid("sysDescr")
          end
        end)

      avg_time_per_resolution = time_microseconds / 100

      # Should be under 100µs per resolution on average
      assert avg_time_per_resolution < 100,
             "Average resolution time was #{avg_time_per_resolution}µs, expected < 100µs"
    end
  end
end
