defmodule BerrypodWeb.AnalyticsHook do
  @moduledoc """
  LiveView on_mount hook for analytics.

  Reads session data prepared by the Plugs.Analytics plug (visitor hash,
  browser, OS, referrer, UTMs) and records pageviews for SPA navigations.

  The Plug records an initial pageview into the ETS buffer with a unique
  `plug_ref`. When JS connects, this hook tells the buffer to drop that
  event (by ref) and records its own pageview with full data (screen_size).
  If JS never connects (no-JS user), the Plug's event flushes to the DB
  after the normal 10-second buffer interval. No timing heuristics needed.

  Screen width is read from the LiveSocket connect params, so it's available
  on every LiveView mount without relying on a separate JS hook event.
  """

  import Phoenix.Component, only: [assign: 3]
  import Phoenix.LiveView, only: [attach_hook: 4, connected?: 1, get_connect_params: 1]

  alias Berrypod.Analytics
  alias Berrypod.Analytics.Buffer

  def on_mount(:track, _params, session, socket) do
    socket =
      socket
      |> assign(:analytics_visitor_hash, session["analytics_visitor_hash"])
      |> assign(:analytics_browser, session["analytics_browser"])
      |> assign(:analytics_os, session["analytics_os"])
      |> assign(:analytics_referrer, session["analytics_referrer"])
      |> assign(:analytics_referrer_source, session["analytics_referrer_source"])
      |> assign(:analytics_utm_source, session["analytics_utm_source"])
      |> assign(:analytics_utm_medium, session["analytics_utm_medium"])
      |> assign(:analytics_utm_campaign, session["analytics_utm_campaign"])
      |> assign(:analytics_country_code, session["country_code"])
      |> assign(:analytics_plug_ref, session["analytics_plug_ref"])

    socket =
      if connected?(socket) do
        # Supersede the Plug's buffered event — we'll record our own with screen_size
        if plug_ref = socket.assigns[:analytics_plug_ref] do
          Buffer.supersede(plug_ref)
        end

        screen_size = screen_size_from_connect_params(socket)

        socket
        |> assign(:analytics_screen_size, screen_size)
        |> assign(:analytics_plug_ref, nil)
        |> attach_hook(:analytics_events, :handle_event, &handle_analytics_event/3)
        |> then(fn s ->
          if s.assigns.analytics_visitor_hash do
            attach_hook(s, :analytics_params, :handle_params, &handle_analytics_params/3)
          else
            s
          end
        end)
      else
        assign(socket, :analytics_screen_size, nil)
      end

    {:cont, socket}
  end

  defp screen_size_from_connect_params(socket) do
    case get_connect_params(socket) do
      %{"screen_width" => width} when is_integer(width) -> classify_screen(width)
      _ -> nil
    end
  end

  defp handle_analytics_params(_params, uri, socket) do
    if admin?(socket) do
      {:cont, socket}
    else
      pathname = URI.parse(uri).path

      Analytics.track_pageview(%{
        pathname: pathname,
        visitor_hash: socket.assigns.analytics_visitor_hash,
        referrer: socket.assigns.analytics_referrer,
        referrer_source: socket.assigns.analytics_referrer_source,
        utm_source: socket.assigns.analytics_utm_source,
        utm_medium: socket.assigns.analytics_utm_medium,
        utm_campaign: socket.assigns.analytics_utm_campaign,
        country_code: socket.assigns.analytics_country_code,
        screen_size: socket.assigns.analytics_screen_size,
        browser: socket.assigns.analytics_browser,
        os: socket.assigns.analytics_os
      })

      # Clear referrer/UTMs after first tracked navigation — they only apply to the entry
      {:cont,
       socket
       |> assign(:analytics_referrer, nil)
       |> assign(:analytics_referrer_source, nil)
       |> assign(:analytics_utm_source, nil)
       |> assign(:analytics_utm_medium, nil)
       |> assign(:analytics_utm_campaign, nil)}
    end
  end

  @doc """
  Extracts common analytics attributes from socket assigns.
  Call sites can merge their own fields (pathname, revenue, etc.) on top.
  """
  def attrs(socket) do
    %{
      visitor_hash: socket.assigns[:analytics_visitor_hash],
      browser: socket.assigns[:analytics_browser],
      os: socket.assigns[:analytics_os],
      screen_size: socket.assigns[:analytics_screen_size],
      country_code: socket.assigns[:analytics_country_code]
    }
  end

  defp handle_analytics_event("analytics:screen", %{"width" => width}, socket)
       when is_integer(width) do
    screen_size = classify_screen(width)
    {:halt, assign(socket, :analytics_screen_size, screen_size)}
  end

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

  defp classify_screen(width) when width < 768, do: "mobile"
  defp classify_screen(width) when width < 1024, do: "tablet"
  defp classify_screen(_width), do: "desktop"

  defp admin?(socket) do
    case socket.assigns[:current_scope] do
      %{user: %{}} -> true
      _ -> false
    end
  end
end
