defmodule Pinchflat.Boot.DataBackfillWorker do
  @moduledoc false

  use Oban.Worker,
    queue: :local_metadata,
    unique: [period: :infinity, states: [:available, :scheduled, :retryable]],
    tags: ["media_item", "media_metadata", "local_metadata", "data_backfill"]

  # This one is going to be a little more self-contained
  # instead of relying on outside modules for the methods.
  # That's because, for now, these methods are not intended
  # to be used elsewhere.
  #
  # I'm just trying out that pattern and seeing if I like it better
  # so this may change.
  import Ecto.Query, warn: false
  require Logger

  alias __MODULE__
  alias Pinchflat.Repo
  alias Pinchflat.Media.MediaItem

  @doc """
  Cancels all pending backfill jobs. Useful for ensuring worker runs immediately
  on app boot.

  Returns {:ok, integer()}
  """
  def cancel_pending_backfill_jobs do
    Oban.Job
    |> where(worker: "Pinchflat.Boot.DataBackfillWorker")
    |> Oban.cancel_all_jobs()
  end

  @impl Oban.Worker
  @doc """
  Performs one-off tasks to get data in the right shape.
  This can be needed when we add new features or change the way
  we store data. Must be idempotent. All new data should already
  conform to the expected schema so this should only be needed
  for existing data. Still runs periodically to be safe.

  Returns :ok
  """
  def perform(%Oban.Job{}) do
    Logger.info("Running data backfill worker")
    backfill_shorts_data()

    reschedule_backfill()

    :ok
  end

  defp backfill_shorts_data do
    query =
      from(
        m in MediaItem,
        where: fragment("? like ?", m.original_url, "%/shorts/%"),
        where: m.short_form_content == false
      )

    {count, _} = Repo.update_all(query, set: [short_form_content: true])

    Logger.info("Backfill worker set short_form_content to true for #{count} media items.")
  end

  defp reschedule_backfill do
    # Run hourly
    next_run_in = 60 * 60

    %{}
    |> DataBackfillWorker.new(schedule_in: next_run_in)
    |> Repo.insert_unique_job()
  end
end
