defmodule Oban.Pro.Migrations.V160 do
  @moduledoc false

  use Ecto.Migration

  def up_ddl(opts) do
    # Partitioning

    alter table(:oban_jobs, prefix: opts.prefix) do
      add_if_not_exists :partition_key, :text,
        generated: """
        ALWAYS AS (CASE WHEN meta ? 'partition_key' THEN meta->>'partition_key' END) STORED
        """
    end

    # Dynamic Queues

    alter table(:oban_queues, prefix: opts.prefix) do
      add_if_not_exists :hash, :text
    end
  end

  def up_idx(opts) do
    # Partitioning

    create_if_not_exists index(
                           :oban_jobs,
                           [:partition_key, :queue, :priority, :scheduled_at, :id],
                           concurrently: opts.concurrently,
                           name: :oban_jobs_partition_index,
                           prefix: opts.prefix,
                           where: "state = 'available' AND partition_key IS NOT NULL"
                         )

    # Workflows

    drop_if_exists index(:oban_jobs, [],
                     concurrently: opts.concurrently,
                     name: :oban_jobs_state_meta_workflow_index,
                     prefix: opts.prefix
                   )

    create_if_not_exists index(
                           :oban_jobs,
                           [
                             "(meta->>'workflow_id')",
                             :state,
                             "(meta->>'on_hold')",
                             "(meta->>'name')"
                           ],
                           concurrently: opts.concurrently,
                           name: :oban_jobs_workflow_index,
                           prefix: opts.prefix,
                           where: "meta ? 'workflow_id'"
                         )

    create_if_not_exists index(
                           :oban_jobs,
                           [
                             "(meta->>'sup_workflow_id')",
                             :state,
                             "(meta->>'on_hold')"
                           ],
                           concurrently: opts.concurrently,
                           name: :oban_jobs_sup_workflow_index,
                           prefix: opts.prefix,
                           where: "meta ? 'sup_workflow_id'"
                         )
  end

  def down_ddl(opts) do
    alter table(:oban_queues, prefix: opts.prefix) do
      remove_if_exists :hash, :text
    end

    alter table(:oban_jobs, prefix: opts.prefix) do
      remove_if_exists :partition_key, :text
    end
  end

  def down_idx(opts) do
    drop_if_exists index(:oban_jobs, [],
                     name: :oban_jobs_partition_index,
                     concurrently: opts.concurrently,
                     prefix: opts.prefix
                   )

    drop_if_exists index(:oban_jobs, [],
                     name: :oban_jobs_workflow_index,
                     concurrently: opts.concurrently,
                     prefix: opts.prefix
                   )

    drop_if_exists index(:oban_jobs, [],
                     name: :oban_jobs_sup_workflow_index,
                     concurrently: opts.concurrently,
                     prefix: opts.prefix
                   )

    create_if_not_exists index(
                           :oban_jobs,
                           [:state, "(meta->>'workflow_id')", "(meta->>'name')"],
                           concurrently: opts.concurrently,
                           name: :oban_jobs_state_meta_workflow_index,
                           prefix: opts.prefix,
                           where: "meta ? 'workflow_id'"
                         )
  end
end
