defmodule AprsmeWeb.MobileChannelTest do
  use AprsmeWeb.ChannelCase

  alias Aprsme.Packet
  alias Aprsme.Repo
  alias AprsmeWeb.MobileUserSocket

  setup do
    # Create test packets with truncated timestamps (no microseconds)
    now = DateTime.truncate(DateTime.utc_now(), :second)

    {:ok, packet1} =
      Repo.insert(%Packet{
        sender: "W5ISP-9",
        base_callsign: "W5ISP",
        lat: Decimal.new("33.1225"),
        lon: Decimal.new("-96.124"),
        received_at: now,
        symbol_table_id: "/",
        symbol_code: ">",
        comment: "Test packet 1"
      })

    {:ok, packet2} =
      Repo.insert(%Packet{
        sender: "W5ISP-1",
        base_callsign: "W5ISP",
        lat: Decimal.new("33.15"),
        lon: Decimal.new("-96.10"),
        received_at: now,
        symbol_table_id: "/",
        symbol_code: ">",
        comment: "Test packet 2"
      })

    {:ok, packet3} =
      Repo.insert(%Packet{
        sender: "K5GVL-10",
        base_callsign: "K5GVL",
        lat: Decimal.new("33.20"),
        lon: Decimal.new("-96.15"),
        received_at: now,
        symbol_table_id: "/",
        symbol_code: "#",
        comment: "Test packet 3"
      })

    {:ok, socket} = connect(MobileUserSocket, %{})
    {:ok, _, socket} = subscribe_and_join(socket, "mobile:packets", %{})

    %{socket: socket, packet1: packet1, packet2: packet2, packet3: packet3}
  end

  describe "join" do
    test "successful join stamps the peer ip and has no other assigns", %{socket: socket} do
      # Socket test client has no real peer_data, so the IP helper falls back
      # to "unknown"; the important part is that the assign is present and
      # no extra per-subscription state has been set yet.
      assigns = Map.get(socket, :assigns)
      assert assigns.peer_ip == "unknown"
      assert Map.delete(assigns, :peer_ip) == %{user_agent: "unknown", packet_queue: []}
      assert {:module, _} = Code.ensure_loaded(AprsmeWeb.MobileChannel)
      assert AprsmeWeb.MobileChannel.__info__(:functions) != []
    end
  end

  describe "subscribe_bounds" do
    test "subscribes to bounds successfully", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, %{bounds: bounds, message: message}
      assert bounds.north == 33.2
      assert bounds.south == 33.0
      assert bounds.east == -96.0
      assert bounds.west == -96.2
      assert message == "Subscribed to packet stream"
    end

    test "rejects invalid bounds - north less than south", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.0,
          "south" => 33.2,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :error, %{message: "North must be greater than south"}
    end

    test "rejects invalid bounds - latitude out of range", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 91.0,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :error, %{message: "Latitude must be between -90 and 90"}
    end

    test "rejects invalid bounds - longitude out of range", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => 181.0,
          "west" => -96.2
        })

      assert_reply ref, :error, %{message: "Longitude must be between -180 and 180"}
    end

    test "accepts integer coordinates and converts to float", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 34,
          "south" => 33,
          "east" => -96,
          "west" => -97
        })

      assert_reply ref, :ok, %{bounds: bounds}
      assert is_float(bounds.north)
      assert is_float(bounds.south)
      assert is_float(bounds.east)
      assert is_float(bounds.west)
    end

    test "rejects invalid numeric strings without crashing", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => "abc",
          "south" => "33.0",
          "east" => "-96.0",
          "west" => "-96.2"
        })

      assert_reply ref, :error, %{message: "All bounds must be numeric"}
    end
  end

  describe "update_bounds" do
    test "updates bounds successfully when subscribed", %{socket: socket} do
      # First subscribe
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      # Then update
      ref =
        push(socket, "update_bounds", %{
          "north" => 33.3,
          "south" => 32.9,
          "east" => -95.9,
          "west" => -96.3
        })

      assert_reply ref, :ok, %{bounds: bounds, message: message}
      assert bounds.north == 33.3
      assert bounds.south == 32.9
      assert message == "Bounds updated"
    end

    test "rejects update when not subscribed", %{socket: socket} do
      ref =
        push(socket, "update_bounds", %{
          "north" => 33.3,
          "south" => 32.9,
          "east" => -95.9,
          "west" => -96.3
        })

      assert_reply ref, :error, %{message: "Not subscribed. Call subscribe_bounds first."}
    end

    test "rejects invalid bounds on update", %{socket: socket} do
      # First subscribe
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      # Try to update with invalid bounds
      ref =
        push(socket, "update_bounds", %{
          "north" => 32.9,
          "south" => 33.3,
          "east" => -95.9,
          "west" => -96.3
        })

      assert_reply ref, :error, %{message: "North must be greater than south"}
    end

    test "rejects invalid numeric strings on update without crashing", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      ref =
        push(socket, "update_bounds", %{
          "north" => "bad",
          "south" => "32.9",
          "east" => "-95.9",
          "west" => "-96.3"
        })

      assert_reply ref, :error, %{message: "All bounds must be numeric"}
    end
  end

  describe "unsubscribe" do
    test "unsubscribes successfully when subscribed", %{socket: socket} do
      # First subscribe
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      # Then unsubscribe
      ref = push(socket, "unsubscribe", %{})
      assert_reply ref, :ok, %{message: "Unsubscribed from packet stream"}
    end

    test "returns message when not subscribed", %{socket: socket} do
      ref = push(socket, "unsubscribe", %{})
      assert_reply ref, :ok, %{message: "Not subscribed"}
    end
  end

  describe "search_callsign" do
    test "searches for callsign with default limit", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP"})

      assert_reply ref, :ok, %{results: results, count: count}
      assert count == length(results)
      assert count >= 0
      # At least W5ISP-9 and W5ISP-1
      assert count >= 2
    end

    test "searches for specific SSID", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP-9"})

      assert_reply ref, :ok, %{results: results, count: count}
      assert count >= 1
      # Should find W5ISP-9
      assert Enum.any?(results, fn r -> r.callsign == "W5ISP-9" end)
    end

    test "searches with wildcard", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP*"})

      assert_reply ref, :ok, %{results: results, count: count}
      assert count >= 2
      # All results should start with W5ISP
      assert Enum.all?(results, fn r -> String.starts_with?(r.callsign, "W5ISP") end)
    end

    test "respects limit parameter", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP", "limit" => 1})

      assert_reply ref, :ok, %{results: _results, count: count}
      assert count <= 1
    end

    test "limits to max of 500", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP", "limit" => 1000})

      assert_reply ref, :ok, %{results: results}
      # Should not crash and should return results
      assert results != []
    end

    test "accepts string limit values", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "W5ISP", "limit" => "1"})

      assert_reply ref, :ok, %{count: count}
      assert count <= 1
    end

    test "normalizes callsign to uppercase", %{socket: socket} do
      ref = push(socket, "search_callsign", %{"query" => "w5isp"})

      assert_reply ref, :ok, %{results: _results, count: count}
      assert count >= 2
    end
  end

  describe "subscribe_callsign" do
    test "subscribes to callsign successfully", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9"})

      assert_reply ref, :ok, %{callsign: callsign, message: message}
      assert callsign == "W5ISP-9"
      assert message == "Subscribed to callsign updates"
    end

    test "subscribes with custom hours_back", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9", "hours_back" => 48})

      assert_reply ref, :ok, %{callsign: "W5ISP-9"}
    end

    test "limits hours_back to maximum of 168", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9", "hours_back" => 200})

      assert_reply ref, :ok, %{callsign: "W5ISP-9"}
      # Should not crash even with hours_back > 168
    end

    test "accepts string hours_back values", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9", "hours_back" => "24"})

      assert_reply ref, :ok, %{callsign: "W5ISP-9"}
    end

    test "normalizes callsign to uppercase", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "w5isp-9"})

      assert_reply ref, :ok, %{callsign: callsign}
      assert callsign == "W5ISP-9"
    end

    test "subscribes with wildcard pattern", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP*"})

      assert_reply ref, :ok, %{callsign: "W5ISP*"}
    end
  end

  describe "unsubscribe_callsign" do
    test "unsubscribes from callsign successfully", %{socket: socket} do
      # First subscribe
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9"})
      assert_reply ref, :ok, _

      # Then unsubscribe
      ref = push(socket, "unsubscribe_callsign", %{})
      assert_reply ref, :ok, %{message: "Unsubscribed from callsign updates"}
    end

    test "returns message when not tracking", %{socket: socket} do
      ref = push(socket, "unsubscribe_callsign", %{})
      assert_reply ref, :ok, %{message: "Not tracking any callsign"}
    end
  end

  describe "streaming packets" do
    test "receives streaming packet when subscribed to bounds", %{socket: socket} do
      # Subscribe to bounds
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      # Simulate streaming packet
      packet = %{
        sender: "TEST-1",
        lat: Decimal.new("33.1"),
        lon: Decimal.new("-96.1"),
        received_at: DateTime.truncate(DateTime.utc_now(), :second)
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      # Should receive the packet
      assert_push "packet", pushed_packet
      assert pushed_packet.callsign == "TEST-1"
    end

    test "filters streaming packet by tracked callsign", %{socket: socket} do
      # Subscribe to callsign
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9"})
      assert_reply ref, :ok, _

      # Clear historical packets from the mailbox
      Process.sleep(100)
      # Consume all pending messages in a loop
      fn ->
        receive do
          _ -> true
        after
          0 -> false
        end
      end
      |> Stream.repeatedly()
      |> Enum.take_while(& &1)

      # Simulate matching packet
      packet1 = %{
        sender: "W5ISP-9",
        lat: Decimal.new("33.1"),
        lon: Decimal.new("-96.1"),
        received_at: DateTime.truncate(DateTime.utc_now(), :second)
      }

      send(socket.channel_pid, {:spatial_packet, packet1})

      # Should receive the packet
      assert_push "packet", pushed_packet
      assert pushed_packet.callsign == "W5ISP-9"

      # Simulate non-matching packet
      packet2 = %{
        sender: "K5GVL-10",
        lat: Decimal.new("33.1"),
        lon: Decimal.new("-96.1"),
        received_at: DateTime.truncate(DateTime.utc_now(), :second)
      }

      send(socket.channel_pid, {:spatial_packet, packet2})

      # Should NOT receive the packet
      refute_push "packet", _
    end

    test "receives live postgres packets after subscribing by callsign only", %{socket: socket} do
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-9"})
      assert_reply ref, :ok, _

      packet = %{
        "sender" => "W5ISP-9",
        "lat" => 33.1,
        "lon" => -96.1,
        "received_at" => DateTime.truncate(DateTime.utc_now(), :second)
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      assert_push "packet", pushed_packet
      assert pushed_packet.callsign == "W5ISP-9"
    end

    test "wildcard callsign matches multiple SSIDs", %{socket: socket} do
      # Subscribe to wildcard
      ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP*"})
      assert_reply ref, :ok, _

      # Simulate packets with different SSIDs
      for ssid <- ["-1", "-9", "-15"] do
        packet = %{
          sender: "W5ISP#{ssid}",
          lat: Decimal.new("33.1"),
          lon: Decimal.new("-96.1"),
          received_at: DateTime.truncate(DateTime.utc_now(), :second)
        }

        send(socket.channel_pid, {:spatial_packet, packet})

        # Should receive all W5ISP-* packets
        assert_push "packet", pushed_packet
        assert String.starts_with?(pushed_packet.callsign, "W5ISP")
      end
    end
  end

  describe "packet data format" do
    test "builds mobile packet with all fields", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      packet = %{
        id: "test-id",
        sender: "W5ISP-9",
        lat: Decimal.new("33.1225"),
        lon: Decimal.new("-96.124"),
        received_at: DateTime.truncate(DateTime.utc_now(), :second),
        symbol_table_id: "/",
        symbol_code: ">",
        comment: "Test comment",
        altitude: 150,
        speed: 45,
        course: 180,
        path: "WIDE1-1,WIDE2-1"
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      assert_push "packet", pushed_packet
      assert pushed_packet.id == "test-id"
      assert pushed_packet.callsign == "W5ISP-9"
      assert pushed_packet.lat == 33.1225
      assert pushed_packet.lng == -96.124
      assert pushed_packet.symbol_table_id == "/"
      assert pushed_packet.symbol_code == ">"
      assert pushed_packet.comment == "Test comment"
      assert pushed_packet.altitude == 150
      assert pushed_packet.speed == 45
      assert pushed_packet.course == 180
      assert pushed_packet.path == "WIDE1-1,WIDE2-1"
      assert byte_size(pushed_packet.timestamp) > 0
    end

    test "omits nil fields from packet data", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      packet = %{
        id: "test-id",
        sender: "W5ISP-9",
        lat: Decimal.new("33.1225"),
        lon: Decimal.new("-96.124"),
        received_at: DateTime.truncate(DateTime.utc_now(), :second),
        symbol_table_id: "/",
        symbol_code: ">",
        comment: nil,
        altitude: nil,
        speed: nil,
        course: nil,
        path: nil
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      assert_push "packet", pushed_packet
      refute Map.has_key?(pushed_packet, :comment)
      refute Map.has_key?(pushed_packet, :altitude)
      refute Map.has_key?(pushed_packet, :speed)
      refute Map.has_key?(pushed_packet, :course)
      refute Map.has_key?(pushed_packet, :path)
    end
  end

  describe "subscribe_bounds with historical options" do
    test "accepts string limit and hours_back values", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2,
          "limit" => "10",
          "hours_back" => "2"
        })

      assert_reply ref, :ok, %{message: "Subscribed to packet stream"}
    end
  end

  describe "packet data type conversions" do
    setup %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _
      :ok
    end

    test "converts integer and binary coordinates to floats, handles NaiveDateTime timestamps",
         %{socket: socket} do
      # Covers to_float(integer), to_float(binary), and format_timestamp(NaiveDateTime).
      {:ok, naive} = NaiveDateTime.new(2026, 1, 1, 12, 0, 0)

      packet = %{
        id: "mixed-1",
        sender: "TYP-1",
        lat: 33,
        lon: "-96.5",
        received_at: naive,
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      assert_push "packet", pushed
      assert pushed.lat == 33.0
      assert pushed.lng == -96.5
      # NaiveDateTime format_timestamp converts to ISO8601.
      assert byte_size(pushed.timestamp) > 0
    end

    test "nil and unparseable coordinates get dropped from the payload", %{socket: socket} do
      packet = %{
        id: "nil-1",
        sender: "TYP-2",
        # nil coordinates → to_float(nil) returns nil and the field is rejected.
        lat: nil,
        lon: nil,
        received_at: DateTime.utc_now(),
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})

      # Packet still pushes but lat/lng are missing (nil fields get stripped).
      assert_push "packet", pushed
      refute Map.has_key?(pushed, :lat)
      refute Map.has_key?(pushed, :lng)
    end
  end

  describe "handle_info catch-all and spatial_packet path" do
    test "ignores unknown messages without changing socket state", %{socket: socket} do
      # Hits the `def handle_info(_message, socket)` catch-all clause.
      send(socket.channel_pid, :totally_unrelated_message)
      # Process must remain alive — proxy via a simple push that requires it.
      send(socket.channel_pid, :another_unknown)
      # If the channel handled both messages without crashing, we're good.
      Process.sleep(20)
      assert Process.alive?(socket.channel_pid)
      assert {:module, _} = Code.ensure_loaded(AprsmeWeb.MobileChannel)
      assert AprsmeWeb.MobileChannel.__info__(:functions) != []
    end

    test "spatial_packet without tracked callsign pushes packet to client", %{socket: socket} do
      packet = %{
        id: "pg-1",
        sender: "PGTEST-1",
        lat: 33.0,
        lon: -96.5,
        received_at: DateTime.utc_now(),
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})
      assert_push "packet", pushed
      assert pushed.lat == 33.0
    end
  end

  describe "type-conversion helper edge cases" do
    setup %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 34.0,
          "south" => 32.0,
          "east" => -96.0,
          "west" => -98.0
        })

      assert_reply ref, :ok, _
      :ok
    end

    test "to_float handles Decimal lat/lon values", %{socket: socket} do
      packet = %{
        id: "dec-1",
        sender: "DEC-1",
        lat: Decimal.new("33.0"),
        lon: Decimal.new("-96.5"),
        received_at: DateTime.utc_now(),
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})
      assert_push "packet", pushed
      assert pushed.lat == 33.0
      assert pushed.lng == -96.5
    end

    test "to_float drops un-castable atom coords", %{socket: socket} do
      packet = %{
        id: "atom-1",
        sender: "ATM-1",
        lat: :not_a_number,
        lon: :still_not,
        received_at: DateTime.utc_now(),
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})
      assert_push "packet", pushed
      refute Map.has_key?(pushed, :lat)
      refute Map.has_key?(pushed, :lng)
    end

    test "format_timestamp returns nil for unsupported value types", %{socket: socket} do
      packet = %{
        id: "ts-1",
        sender: "TS-1",
        lat: 33.0,
        lon: -96.0,
        # Non-DateTime/NaiveDateTime/nil — format_timestamp(_) → nil → field stripped.
        received_at: 12_345,
        symbol_table_id: "/",
        symbol_code: ">"
      }

      send(socket.channel_pid, {:spatial_packet, packet})
      assert_push "packet", pushed
      refute Map.has_key?(pushed, :timestamp)
    end
  end

  describe "subscribe_bounds limit and hours_back parsing" do
    test "ensure_integer parses string limit and hours_back from payload", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 34.0,
          "south" => 32.0,
          "east" => -95.0,
          "west" => -97.0,
          "limit" => "42",
          "hours_back" => "2"
        })

      assert_reply ref, :ok, _
    end

    test "ensure_integer falls back to default for unparseable limit/hours_back", %{socket: socket} do
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 34.0,
          "south" => 32.0,
          "east" => -95.0,
          "west" => -97.0,
          "limit" => "not-a-number",
          "hours_back" => :atom
        })

      # Defaults kick in; the call should still succeed.
      assert_reply ref, :ok, _
    end
  end

  describe "rate limiting" do
    setup %{socket: socket} do
      # Subscribe and wait for historical batch pushes, then drain the mailbox
      ref =
        push(socket, "subscribe_bounds", %{
          "north" => 33.2,
          "south" => 33.0,
          "east" => -96.0,
          "west" => -96.2
        })

      assert_reply ref, :ok, _

      # Drain any historical packet pushes
      drain_mailbox()

      :ok
    end

    test "subscribe_bounds is rate-limited after repeated calls", %{socket: socket} do
      # Call subscribe_bounds many times with different bounds — each call re-subscribes
      bounds = %{"north" => 33.2, "south" => 33.0, "east" => -96.0, "west" => -96.2}

      results =
        Enum.map(1..35, fn i ->
          bounds = Map.put(bounds, "north", 33.0 + i * 0.01)
          ref = push(socket, "subscribe_bounds", bounds)
          assert_reply ref, status, _, 500
          status
        end)

      # At least some requests should be denied
      assert :error in results
    end

    test "search_callsign is rate-limited after repeated calls", %{socket: socket} do
      results =
        Enum.map(1..35, fn _i ->
          ref = push(socket, "search_callsign", %{"query" => "W5ISP"})
          assert_reply ref, status, _, 500
          status
        end)

      assert :error in results
    end

    test "subscribe_callsign is rate-limited after repeated calls", %{socket: socket} do
      results =
        Enum.map(1..35, fn i ->
          ref = push(socket, "subscribe_callsign", %{"callsign" => "W5ISP-#{i}"})
          assert_reply ref, status, _, 500
          status
        end)

      assert :error in results
    end

    defp drain_mailbox do
      receive do
        _ -> drain_mailbox()
      after
        50 -> :ok
      end
    end
  end
end
