defmodule PlausibleWeb.Live.GoalSettingsTest do
  use PlausibleWeb.ConnCase, async: true
  use Plausible.Teams.Test
  import Phoenix.LiveViewTest
  import Plausible.Test.Support.HTML

  describe "GET /:domain/settings/goals" do
    setup [:create_user, :log_in, :create_site]

    @tag :ee_only
    test "lists goals for the site and renders links", %{conn: conn, site: site} do
      {:ok, [g1, g2, g3]} = setup_goals(site)
      conn = get(conn, "/#{site.domain}/settings/goals")

      resp = html_response(conn, 200)
      assert resp =~ "Define actions that you want your users to take"
      assert resp =~ "compose goals into funnels"
      assert resp =~ "/#{URI.encode_www_form(site.domain)}/settings/funnels"
      assert element_exists?(resp, ~s|a[href="https://plausible.io/docs/goal-conversions"]|)

      assert resp =~ to_string(g1)
      assert resp =~ "Pageview"
      assert resp =~ to_string(g2)
      assert resp =~ "Custom Event"
      assert resp =~ to_string(g3)
      assert resp =~ "Revenue Goal (EUR)"
    end

    @tag :ee_only
    test "lists Revenue Goals with feature availability annotation if the plan does not cover them",
         %{conn: conn, user: user, site: site} do
      {:ok, [_, _, g3]} = setup_goals(site)

      user
      |> team_of()
      |> Plausible.Teams.Team.end_trial()
      |> Plausible.Repo.update!()

      conn = get(conn, "/#{site.domain}/settings/goals")

      resp = html_response(conn, 200)

      assert g3.currency
      assert resp =~ to_string(g3)
      assert resp =~ "Upgrade Required"

      refute element_exists?(
               resp,
               ~s/button[phx-click="edit-goal"][phx-value-goal-id="#{g3.id}"][disabled]#edit-goal-#{g3.id}/
             )
    end

    test "lists goals with actions", %{conn: conn, site: site} do
      {:ok, goals} = setup_goals(site)
      conn = get(conn, "/#{site.domain}/settings/goals")
      resp = html_response(conn, 200)

      for g <- goals do
        assert element_exists?(
                 resp,
                 ~s/button[phx-click="delete-goal"][phx-value-goal-id="#{g.id}"]#delete-goal-#{g.id}/
               )

        assert element_exists?(
                 resp,
                 ~s/button[phx-click="edit-goal"][phx-value-goal-id="#{g.id}"]#edit-goal-#{g.id}/
               )
      end
    end

    test "if no goals are present, a proper info is displayed", %{conn: conn, site: site} do
      conn = get(conn, "/#{site.domain}/settings/goals")
      resp = html_response(conn, 200)
      assert resp =~ "No goals configured for this site"
    end

    test "if goals are present, no info about missing goals is displayed", %{
      conn: conn,
      site: site
    } do
      {:ok, _goals} = setup_goals(site)
      conn = get(conn, "/#{site.domain}/settings/goals")
      resp = html_response(conn, 200)
      refute resp =~ "No goals configured for this site"
    end

    test "add goal button is rendered", %{conn: conn, site: site} do
      conn = get(conn, "/#{site.domain}/settings/goals")
      resp = html_response(conn, 200)
      assert element_exists?(resp, ~s/button#add-goal-button[phx-click="add-goal"]/)
    end

    test "search goals input is rendered", %{conn: conn, site: site} do
      conn = get(conn, "/#{site.domain}/settings/goals")
      resp = html_response(conn, 200)
      assert element_exists?(resp, ~s/input[type="text"]#filter-text/)
      assert element_exists?(resp, ~s/form[phx-change="filter"]#filter-form/)
    end
  end

  describe "GoalSettings live view" do
    setup [:create_user, :log_in, :create_site]

    test "allows goal deletion", %{conn: conn, site: site} do
      {:ok, [g1, g2 | _]} = setup_goals(site)
      {lv, html} = get_liveview(conn, site, with_html?: true)

      assert html =~ to_string(g1)
      assert html =~ to_string(g2)

      html = lv |> element(~s/button#delete-goal-#{g1.id}/) |> render_click()

      refute html =~ to_string(g1)
      assert html =~ to_string(g2)

      html = get(conn, "/#{site.domain}/settings/goals") |> html_response(200)

      refute html =~ to_string(g1)
      assert html =~ to_string(g2)
    end

    test "allows list filtering / search", %{conn: conn, site: site} do
      {:ok, [g1, g2, g3]} = setup_goals(site)
      {lv, html} = get_liveview(conn, site, with_html?: true)

      assert html =~ to_string(g1)
      assert html =~ to_string(g2)
      assert html =~ to_string(g3)

      html = type_into_search(lv, to_string(g3))

      refute html =~ to_string(g1)
      refute html =~ to_string(g2)
      assert html =~ to_string(g3)
    end

    test "allows resetting filter text via backspace icon", %{conn: conn, site: site} do
      {:ok, [g1, g2, g3]} = setup_goals(site)
      {lv, html} = get_liveview(conn, site, with_html?: true)

      refute element_exists?(html, ~s/svg[phx-click="reset-filter-text"]#reset-filter/)

      html = type_into_search(lv, to_string(g3))

      assert element_exists?(html, ~s/svg[phx-click="reset-filter-text"]#reset-filter/)

      html = lv |> element(~s/svg#reset-filter/) |> render_click()

      assert html =~ to_string(g1)
      assert html =~ to_string(g2)
      assert html =~ to_string(g3)
    end

    test "allows resetting filter text via no match link", %{conn: conn, site: site} do
      {:ok, _goals} = setup_goals(site)
      lv = get_liveview(conn, site)
      html = type_into_search(lv, "Definitely this is not going to render any matches")

      assert html =~ "No goals found for this site. Please refine or"
      assert html =~ "reset your search"

      assert element_exists?(html, ~s/a[phx-click="reset-filter-text"]#reset-filter-hint/)
      html = lv |> element(~s/a#reset-filter-hint/) |> render_click()

      refute html =~ "No goals found for this site. Please refine or"
    end

    test "auto-configuring custom event goals", %{conn: conn, site: site} do
      populate_stats(site, [
        build(:event, name: "Signup"),
        build(:event, name: "Newsletter Signup"),
        build(:event, name: "Purchase")
      ])

      autoconfigure_button_selector = ~s/button[phx-click="autoconfigure"]/

      assert_suggested_event_name_count = fn html, number ->
        assert text_of_element(html, autoconfigure_button_selector) =~
                 "found #{number} custom events from the last 6 months that are not yet configured as goals"
      end

      {lv, html} = get_liveview(conn, site, with_html?: true)

      # At first, 3 event names are suggested
      assert_suggested_event_name_count.(html, 3)

      # Add one goal
      lv
      |> element("#goals-form-modal form")
      |> render_submit(%{goal: %{event_name: "Signup"}})

      html = render(lv)

      # Now two goals are suggested because one is already added
      assert_suggested_event_name_count.(html, 2)

      # Delete the goal
      goal = Plausible.Repo.get_by(Plausible.Goal, site_id: site.id, event_name: "Signup")
      html = lv |> element(~s/button#delete-goal-#{goal.id}/) |> render_click()

      # Suggested event name count should be 3 again
      assert_suggested_event_name_count.(html, 3)

      # Autoconfigure all custom event goals
      lv
      |> element(autoconfigure_button_selector)
      |> render_click()

      html = render(lv)

      # All possible goals exist - no suggestions anymore
      refute html =~ "from the last 6 months"
    end
  end

  defp setup_goals(site) do
    {:ok, g1} = Plausible.Goals.create(site, %{"page_path" => "/go/to/blog/**"})
    {:ok, g2} = Plausible.Goals.create(site, %{"event_name" => "Register"})
    {:ok, g3} = Plausible.Goals.create(site, %{"event_name" => "Purchase", "currency" => "EUR"})
    {:ok, [g1, g2, g3]}
  end

  defp get_liveview(conn, site, opts \\ []) do
    conn = assign(conn, :live_module, PlausibleWeb.Live.GoalSettings)
    {:ok, lv, html} = live(conn, "/#{site.domain}/settings/goals")

    if Keyword.get(opts, :with_html?) do
      {lv, html}
    else
      lv
    end
  end

  defp type_into_search(lv, text) do
    lv
    |> element("form#filter-form")
    |> render_change(%{
      "_target" => ["filter-text"],
      "filter-text" => "#{text}"
    })
  end
end
