defmodule BerrypodWeb.Plugs.AnalyticsTest do
  use BerrypodWeb.ConnCase, async: false

  import Ecto.Query

  alias Berrypod.Analytics.{Buffer, Event}
  alias Berrypod.Repo

  setup do
    send(Buffer, :flush)
    :timer.sleep(50)
    Repo.delete_all(Event)
    :ok
  end

  describe "analytics plug" do
    test "records a pageview on GET request", %{conn: conn} do
      conn
      |> put_req_header("user-agent", "Mozilla/5.0 Chrome/120.0")
      |> get(~p"/")

      send(Buffer, :flush)
      :timer.sleep(50)

      events =
        from(e in Event, where: e.pathname == "/" and e.name == "pageview")
        |> Repo.all()

      assert length(events) >= 1
      event = hd(events)
      assert event.browser == "Chrome"
    end

    test "does not record on POST request", %{conn: conn} do
      count_before = Repo.aggregate(Event, :count)

      conn
      |> put_req_header("user-agent", "Mozilla/5.0 Chrome/120.0")
      |> post(~p"/checkout", %{})

      send(Buffer, :flush)
      :timer.sleep(50)

      count_after = Repo.aggregate(Event, :count)
      assert count_after == count_before
    end

    test "skips bots", %{conn: conn} do
      count_before = Repo.aggregate(Event, :count)

      conn
      |> put_req_header("user-agent", "Googlebot/2.1 (+http://www.google.com/bot.html)")
      |> get(~p"/")

      send(Buffer, :flush)
      :timer.sleep(50)

      count_after = Repo.aggregate(Event, :count)
      assert count_after == count_before
    end

    test "stores analytics data in session", %{conn: conn} do
      conn =
        conn
        |> put_req_header("user-agent", "Mozilla/5.0 Firefox/121.0")
        |> get(~p"/")

      assert get_session(conn, "analytics_visitor_hash") |> is_binary()
      assert get_session(conn, "analytics_browser") == "Firefox"
    end

    test "stores plug_ref in session for buffer supersede", %{conn: conn} do
      conn =
        conn
        |> put_req_header("user-agent", "Mozilla/5.0 Chrome/120.0")
        |> get(~p"/")

      plug_ref = get_session(conn, "analytics_plug_ref")
      assert is_binary(plug_ref)
      assert String.length(plug_ref) == 36
    end

    test "extracts referrer", %{conn: conn} do
      conn
      |> put_req_header("user-agent", "Mozilla/5.0 Chrome/120.0")
      |> put_req_header("referer", "https://www.google.com/search?q=test")
      |> get(~p"/")

      send(Buffer, :flush)
      :timer.sleep(50)

      event =
        from(e in Event,
          where: e.referrer == "google.com",
          order_by: [desc: e.inserted_at],
          limit: 1
        )
        |> Repo.one()

      assert event
      assert event.referrer_source == "Google"
    end

    test "extracts UTM params", %{conn: conn} do
      conn
      |> put_req_header("user-agent", "Mozilla/5.0 Chrome/120.0")
      |> get(~p"/?utm_source=newsletter&utm_medium=email&utm_campaign=spring")

      send(Buffer, :flush)
      :timer.sleep(50)

      event =
        from(e in Event,
          where: e.utm_source == "newsletter",
          order_by: [desc: e.inserted_at],
          limit: 1
        )
        |> Repo.one()

      assert event
      assert event.utm_medium == "email"
      assert event.utm_campaign == "spring"
    end
  end
end
