defmodule AprsIsMockTest do
  use ExUnit.Case, async: false

  setup do
    if Process.whereis(AprsIsMock) do
      GenServer.stop(AprsIsMock, :normal)
      # Give OTP a moment to unregister the name
      Process.sleep(10)
    end

    on_exit(fn ->
      if Process.whereis(AprsIsMock) do
        try do
          GenServer.stop(AprsIsMock, :normal, 100)
        catch
          :exit, _ -> :ok
        end
      end
    end)

    :ok
  end

  describe "get_status/0" do
    test "returns a default disconnected status when not running" do
      status = AprsIsMock.get_status()

      assert status.connected == false
      assert status.server == "mock.aprs.test"
      assert status.port == 14_580
      assert is_nil(status.connected_at)
      assert status.packet_stats.total_packets == 0
      assert is_nil(status.packet_stats.last_packet_at)
      assert status.packet_stats.packets_per_second == 0
      assert status.stored_packet_count == 0
    end

    test "computes uptime when the mock is connected" do
      {:ok, _} = AprsIsMock.start_link([])
      :ok = AprsIsMock.simulate_connection_state(true)

      # Small sleep so uptime has a non-zero value.
      Process.sleep(10)
      status = AprsIsMock.get_status()

      assert status.connected == true
      assert status.uptime_seconds >= 0
    end

    test "returns uptime 0 when no connected_at is set" do
      {:ok, _} = AprsIsMock.start_link([])
      status = AprsIsMock.get_status()
      assert status.uptime_seconds == 0
    end
  end

  describe "send_message and filter helpers" do
    test "filter helpers are :ok no-ops" do
      assert AprsIsMock.set_filter("r/0/0/1") == :ok
      assert AprsIsMock.list_active_filters() == :ok
    end

    test "three-arg send_message is a :ok no-op without running server" do
      assert AprsIsMock.send_message("TEST", "DEST", "hi") == :ok
    end

    test "single-arg send_message dispatches to server when running" do
      {:ok, _} = AprsIsMock.start_link([])
      assert AprsIsMock.send_message("hi") == :ok
    end
  end

  describe "simulate_packet/1" do
    test "broadcasts to the endpoint without crashing" do
      # Endpoint is started at boot in test env, so this just needs to not raise.
      assert AprsIsMock.simulate_packet(%{sender: "TEST"}) == :ok
    end
  end

  describe "terminate/2" do
    test "returns :ok on termination" do
      {:ok, _} = AprsIsMock.start_link([])
      assert :ok = AprsIsMock.stop()
    end
  end

  describe "handle_info/2" do
    test "ignores arbitrary messages" do
      {:ok, pid} = AprsIsMock.start_link([])
      send(pid, :arbitrary_message)
      Process.sleep(10)
      assert Process.alive?(pid)
    end
  end
end
