defmodule Plausible.ConsolidatedViewTest do
  use Plausible

  on_ee do
    use Plausible.DataCase, async: true
    import Ecto.Query
    alias Plausible.ConsolidatedView
    import Plausible.Teams.Test

    describe "enable/1 and enabled?/1" do
      setup [:create_user, :create_team]

      test "creates and persists a new consolidated site instance", %{team: team} do
        new_site(team: team)
        assert {:ok, %Plausible.Site{consolidated: true}} = ConsolidatedView.enable(team)
        assert ConsolidatedView.enabled?(team)
      end

      test "is idempotent", %{team: team} do
        new_site(team: team)
        assert {:ok, s1} = ConsolidatedView.enable(team)
        assert {:ok, s2} = ConsolidatedView.enable(team)

        assert 1 =
                 from(s in Plausible.ConsolidatedView.sites(), where: s.team_id == ^team.id)
                 |> Plausible.Repo.aggregate(:count)

        assert s1.domain == s2.domain
      end

      test "returns {:error, :no_sites} when the team does not have any sites", %{team: team} do
        assert {:error, :no_sites} = ConsolidatedView.enable(team)
        refute ConsolidatedView.enabled?(team)
      end

      @tag :skip
      test "returns {:error, :upgrade_required} when team ineligible for this feature"

      test "creates consolidated view with stats start dates of the oldest site", %{team: team} do
        datetimes = [
          ~N[2024-01-01 12:00:00],
          ~N[2024-01-01 11:00:00],
          ~N[2024-02-01 12:00:00]
        ]

        for dt <- datetimes, do: new_site(team: team, native_stats_start_at: dt)

        {:ok, view} = ConsolidatedView.enable(team)

        min = Enum.min(datetimes)
        assert view.native_stats_start_at == min
        assert view.stats_start_date == NaiveDateTime.to_date(min)
      end

      test "enable/1 updates cache", %{team: team} do
        site = new_site(team: team)
        {:ok, _} = ConsolidatedView.enable(team)

        assert eventually(fn ->
                 {ConsolidatedView.Cache.get(team.identifier) == [site.id], :ok}
               end)
      end
    end

    describe "disable/1" do
      setup [:create_user, :create_team, :create_site]

      setup %{team: team} do
        ConsolidatedView.enable(team)
        :ok
      end

      test "deletes an existing consolidated site instance", %{team: team} do
        assert ConsolidatedView.get(team)

        assert :ok = ConsolidatedView.disable(team)

        refute ConsolidatedView.get(team)
      end

      test "is idempotent", %{team: team} do
        assert :ok = ConsolidatedView.disable(team)
        assert :ok = ConsolidatedView.disable(team)

        refute ConsolidatedView.get(team)
      end
    end

    describe "site_ids/1" do
      setup [:create_user, :create_team, :create_site]

      test "returns {:error, :not_found} when no consolidated view exists", %{team: team} do
        assert {:error, :not_found} = ConsolidatedView.site_ids(team)
      end

      test "returns site_ids owned by the team when consolidated view exists", %{
        team: team,
        site: site
      } do
        ConsolidatedView.enable(team)
        assert ConsolidatedView.site_ids(team) == {:ok, [site.id]}
      end
    end

    describe "get/1" do
      setup [:create_user, :create_team, :create_site]

      test "can get by team", %{team: team} do
        assert is_nil(ConsolidatedView.get(team))
        ConsolidatedView.enable(team)
        assert %Plausible.Site{} = ConsolidatedView.get(team)
      end

      test "can get by team.identifier", %{team: team} do
        assert is_nil(ConsolidatedView.get(team.identifier))
        ConsolidatedView.enable(team)
        assert %Plausible.Site{} = ConsolidatedView.get(team.identifier)
      end
    end

    # see also: Site.RemovalTest and Sites.TransferTest
    describe "reset_if_enabled/1" do
      setup [:create_user, :create_team]

      test "no-op if disabled", %{team: team} do
        :ok = ConsolidatedView.reset_if_enabled(team)
        refute ConsolidatedView.enabled?(team)
        refute ConsolidatedView.get(team)
      end

      @tag :slow
      test "re-enables", %{team: team} do
        _site = new_site(team: team, native_stats_start_at: ~N[2024-01-01 12:00:00])

        {:ok, first_enable} = ConsolidatedView.enable(team)

        another_site = new_site(team: team, native_stats_start_at: ~N[2024-01-01 10:00:00])

        Process.sleep(1_000)

        :ok = ConsolidatedView.reset_if_enabled(team)
        assert ConsolidatedView.enabled?(team)

        consolidated_view = ConsolidatedView.get(team)
        assert consolidated_view.native_stats_start_at == another_site.native_stats_start_at
        assert NaiveDateTime.after?(consolidated_view.updated_at, first_enable.updated_at)
      end
    end
  end
end
