defmodule AprsmeWeb.MapLive.NavigationTest do
  # Logger.info calls are fine during tests; we don't silence them.
  use ExUnit.Case, async: true

  alias AprsmeWeb.MapLive.Navigation
  alias Phoenix.LiveView.Socket

  describe "determine_map_location/2" do
    test "explicit URL params win over IP geolocation" do
      params = %{"lat" => "40.0", "lng" => "-95.0", "z" => "7"}
      session = %{"ip_geolocation" => %{"lat" => 10.0, "lng" => 20.0}}

      assert {%{lat: 40.0, lng: -95.0}, 7, false} =
               Navigation.determine_map_location(params, session)
    end

    test "valid IP geolocation used when no explicit URL params" do
      session = %{"ip_geolocation" => %{"lat" => 45.5, "lng" => -122.6}}
      assert {%{lat: 45.5, lng: -122.6}, 11, true} = Navigation.determine_map_location(%{}, session)
    end

    test "missing or invalid geolocation falls back to URL defaults" do
      # No geolocation and no URL params → default center + skip_initial_url_update=true
      assert {%{lat: _, lng: _}, _zoom, true} = Navigation.determine_map_location(%{}, %{})

      # Geolocation present but with non-numeric values → fall back
      session = %{"ip_geolocation" => %{"lat" => "not-a-number", "lng" => "nope"}}
      assert {%{lat: _, lng: _}, _zoom, true} = Navigation.determine_map_location(%{}, session)
    end

    test "URL params win even with malformed geolocation" do
      session = %{"ip_geolocation" => %{"lat" => "oops", "lng" => "oops"}}
      params = %{"lat" => "10.0"}
      {_, _, skip?} = Navigation.determine_map_location(params, session)
      assert skip? == false
    end
  end

  describe "handle_callsign_tracking/4" do
    @default_center %{lat: 10.0, lng: 20.0}
    @default_zoom 5

    test "empty callsign returns unchanged center and zoom" do
      assert Navigation.handle_callsign_tracking("", @default_center, @default_zoom, false) ==
               {@default_center, @default_zoom}

      assert Navigation.handle_callsign_tracking("", @default_center, @default_zoom, true) ==
               {@default_center, @default_zoom}
    end

    test "when explicit URL params are set, tracking is bypassed" do
      assert Navigation.handle_callsign_tracking("K5ABC", @default_center, @default_zoom, true) ==
               {@default_center, @default_zoom}
    end

    test "returns defaults when the database lookup raises" do
      # With a callsign that won't match any test data and no DB ownership,
      # the rescue clause returns the defaults.
      assert Navigation.handle_callsign_tracking(
               "NONEXISTENT-99",
               @default_center,
               @default_zoom,
               false
             ) == {@default_center, @default_zoom}
    end
  end

  describe "handle_callsign_search/2" do
    test "empty string returns the socket untouched" do
      socket = %Socket{assigns: %{__changed__: %{}}}
      assert {:noreply, ^socket} = Navigation.handle_callsign_search("", socket)
    end

    test "invalid callsign puts a flash error" do
      socket = %Socket{assigns: %{__changed__: %{}, flash: %{}}}
      {:noreply, result} = Navigation.handle_callsign_search("HELLO WORLD", socket)
      assert result.assigns.flash["error"] == "Invalid callsign format"
    end

    test "valid callsign triggers push_navigate" do
      socket = %Socket{
        assigns: %{__changed__: %{}, flash: %{}},
        redirected: nil
      }

      {:noreply, result} = Navigation.handle_callsign_search("K5ABC-9", socket)
      # push_navigate/2 sets the `redirected` field on the socket.
      assert result.redirected
    end
  end

  describe "update_and_zoom_to_location/4" do
    test "sets map_center and map_zoom assigns, and pushes a zoom event" do
      socket = %Socket{assigns: %{__changed__: %{}}}
      result = Navigation.update_and_zoom_to_location(socket, 30.5, -95.0, 8)
      assert result.assigns.map_center == %{lat: 30.5, lng: -95.0}
      assert result.assigns.map_zoom == 8
    end
  end

  describe "zoom_to_current_location/1" do
    test "pushes a zoom_to_location event using the socket's center/zoom" do
      socket = %Socket{
        assigns: %{__changed__: %{}, map_center: %{lat: 1.0, lng: 2.0}, map_zoom: 10}
      }

      # The function returns the socket (with push_event recorded).
      result = Navigation.zoom_to_current_location(socket)
      assert %Socket{} = result
    end
  end
end
