defmodule Mix.Tasks.CompactDatabase do
  @moduledoc """
  Compact the database by flattening the object graph.
  """

  require Logger

  use Mix.Task
  import Ecto.Query
  alias Pleroma.Activity
  alias Pleroma.Repo

  defp maybe_compact(%Activity{data: %{"object" => %{"id" => object_id}}} = activity) do
    data =
      activity.data
      |> Map.put("object", object_id)

    {:ok, activity} =
      Activity.change(activity, %{data: data})
      |> Repo.update()

    {:ok, activity}
  end

  defp maybe_compact(%Activity{} = activity), do: {:ok, activity}

  defp activity_query(min_id, max_id) do
    from(
      a in Activity,
      where: fragment("?->>'type' = 'Create'", a.data),
      where: a.id >= ^min_id,
      where: a.id < ^max_id
    )
  end

  def run(_args) do
    Application.ensure_all_started(:pleroma)

    max = Repo.aggregate(Activity, :max, :id)
    Logger.info("Considering #{max} activities")

    chunks = 0..round(max / 100)

    Enum.each(chunks, fn i ->
      min = i * 100
      max = min + 100

      activity_query(min, max)
      |> Repo.all()
      |> Enum.each(&maybe_compact/1)

      IO.write(".")
    end)

    Logger.info("Finished.")
  end
end