defmodule BerrypodWeb.NewsletterHook do
  @moduledoc """
  LiveView on_mount hook for newsletter signup across all shop pages.

  Uses `attach_hook/4` to intercept `newsletter_subscribe` events globally
  without modifying individual shop LiveViews.
  """

  import Phoenix.Component, only: [assign: 3]
  import Phoenix.LiveView, only: [attach_hook: 4]

  alias Berrypod.Newsletter

  def on_mount(:mount_newsletter, _params, _session, socket) do
    enabled = Newsletter.newsletter_enabled?()

    socket =
      socket
      |> assign(:newsletter_enabled, enabled)
      |> assign(:newsletter_state, :idle)
      |> assign(:newsletter_ip_hash, hash_ip(socket))
      |> attach_hook(:newsletter, :handle_event, &handle_newsletter_event/3)

    {:cont, socket}
  end

  defp handle_newsletter_event("newsletter_subscribe", %{"email" => email}, socket) do
    if socket.assigns.newsletter_enabled do
      case Newsletter.subscribe(email,
             consent_text: "Newsletter signup on website",
             ip_hash: socket.assigns.newsletter_ip_hash
           ) do
        {:ok, _} ->
          {:halt, assign(socket, :newsletter_state, :submitted)}

        {:already_confirmed, _} ->
          {:halt, assign(socket, :newsletter_state, :submitted)}

        {:error, _} ->
          {:halt, assign(socket, :newsletter_state, :error)}
      end
    else
      {:halt, assign(socket, :newsletter_state, :disabled)}
    end
  end

  defp handle_newsletter_event(_event, _params, socket), do: {:cont, socket}

  # connect_info is only available during mount, so we hash and store it early
  defp hash_ip(socket) do
    case Phoenix.LiveView.get_connect_info(socket, :peer_data) do
      %{address: ip} ->
        daily_salt = Date.utc_today() |> Date.to_iso8601()
        :crypto.hash(:sha256, :inet.ntoa(ip) ++ [daily_salt]) |> Base.encode16(case: :lower)

      _ ->
        nil
    end
  end
end
