defmodule AprsmeWeb.LocaleHookTest do
  # on_mount/4 mutates the process-wide Gettext locale and reads app env;
  # serialize with anything else that does the same.
  use ExUnit.Case, async: false

  alias AprsmeWeb.LocaleHook
  alias Phoenix.LiveView.Socket

  setup do
    original_env = Application.get_env(:aprsme, :env)
    original_locale = Gettext.get_locale(AprsmeWeb.Gettext)

    on_exit(fn ->
      Application.put_env(:aprsme, :env, original_env)
      Gettext.put_locale(AprsmeWeb.Gettext, original_locale)
    end)

    :ok
  end

  defp bare_socket do
    %Socket{
      assigns: %{__changed__: %{}},
      private: %{}
    }
  end

  describe "on_mount/4 in production" do
    setup do
      Application.put_env(:aprsme, :env, :prod)
      :ok
    end

    test "sets a supported locale from session" do
      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{"locale" => "es"}, bare_socket())
      assert socket.assigns.locale == "es"
      assert Gettext.get_locale(AprsmeWeb.Gettext) == "es"
    end

    test "falls back to 'en' for unsupported session locale" do
      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{"locale" => "zz"}, bare_socket())
      assert socket.assigns.locale == "en"
    end

    test "falls back to 'en' when session has no locale" do
      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{}, bare_socket())
      assert socket.assigns.locale == "en"
    end

    test "accepts all declared supported locales" do
      for loc <- ["en", "es", "de", "fr"] do
        {:cont, socket} =
          LocaleHook.on_mount(:set_locale, %{}, %{"locale" => loc}, bare_socket())

        assert socket.assigns.locale == loc
      end
    end
  end

  describe "on_mount/4 in non-prod" do
    test "leaves locale assign as nil" do
      Application.put_env(:aprsme, :env, :dev)
      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{"locale" => "es"}, bare_socket())
      assert socket.assigns.locale == nil
    end
  end

  describe "on_mount/4 map_page assign" do
    test "map_page is false for non-MapLive socket" do
      Application.put_env(:aprsme, :env, :dev)
      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{}, bare_socket())
      assert socket.assigns.map_page == false
    end

    test "map_page is true when the socket's view is MapLive.Index" do
      Application.put_env(:aprsme, :env, :dev)

      socket = %Socket{
        assigns: %{__changed__: %{}},
        private: %{phoenix_live_view: %{view: AprsmeWeb.MapLive.Index}}
      }

      {:cont, socket} = LocaleHook.on_mount(:set_locale, %{}, %{}, socket)
      assert socket.assigns.map_page == true
    end
  end
end
