defmodule BerrypodWeb.Plugs.Analytics do
  @moduledoc """
  Plug that records an initial pageview and prepares analytics session data.

  Fires on every GET request regardless of JS — computes a privacy-friendly
  visitor hash, parses the user agent, extracts referrer and UTM params.
  Records the pageview immediately (for no-JS support) and stores the data
  in the session for the LiveView hook to use on SPA navigations.

  The event is recorded with a known ID (plug_ref) stored in the session.
  When JS connects, the LiveView hook supersedes this event by ID and
  records its own with full data (screen_size). If JS never connects,
  the Plug's event flushes to the DB normally.
  """

  import Plug.Conn

  alias Berrypod.Analytics
  alias Berrypod.Analytics.{Salt, UAParser, Referrer}

  def init(opts), do: opts

  def call(%{method: "GET"} = conn, _opts) do
    ua = get_req_header(conn, "user-agent") |> List.first("")
    {browser, os} = UAParser.parse(ua)

    # Skip bots
    if browser == "Bot" do
      conn
    else
      # Skip recording for logged-in admin — don't set analytics session
      # data either, so downstream guards (visitor_hash checks in LiveViews)
      # naturally filter out admin browsing for all event types
      if admin?(conn) do
        conn
      else
        record_and_prepare(conn, ua, browser, os)
      end
    end
  end

  def call(conn, _opts), do: conn

  defp record_and_prepare(conn, ua, browser, os) do
    visitor_hash = Salt.hash_visitor(conn.remote_ip, ua)
    {referrer, referrer_source} = extract_referrer(conn)
    utm = extract_utms(conn)
    country_code = get_session(conn, "country_code")
    plug_ref = Ecto.UUID.generate()

    Analytics.track_pageview(%{
      id: plug_ref,
      pathname: conn.request_path,
      visitor_hash: visitor_hash,
      referrer: referrer,
      referrer_source: referrer_source,
      utm_source: utm.source,
      utm_medium: utm.medium,
      utm_campaign: utm.campaign,
      country_code: country_code,
      screen_size: nil,
      browser: browser,
      os: os
    })

    conn
    |> put_session("analytics_visitor_hash", visitor_hash)
    |> put_session("analytics_browser", browser)
    |> put_session("analytics_os", os)
    |> put_session("analytics_referrer", referrer)
    |> put_session("analytics_referrer_source", referrer_source)
    |> put_session("analytics_utm_source", utm.source)
    |> put_session("analytics_utm_medium", utm.medium)
    |> put_session("analytics_utm_campaign", utm.campaign)
    |> put_session("analytics_plug_ref", plug_ref)
  end

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

  defp extract_referrer(conn) do
    referrer_url = get_req_header(conn, "referer") |> List.first()
    {referrer, source} = Referrer.parse(referrer_url)

    # Don't count self-referrals
    host = conn.host

    if referrer && referrer == host do
      {nil, nil}
    else
      {referrer, source}
    end
  end

  defp extract_utms(conn) do
    params = conn.query_params || %{}

    %{
      source: Map.get(params, "utm_source"),
      medium: Map.get(params, "utm_medium"),
      campaign: Map.get(params, "utm_campaign")
    }
  end
end
