defmodule Microwaveprop.Repo.Migrations.TightenGridTasksClaimIndex do
  use Ecto.Migration

  # CREATE INDEX CONCURRENTLY requires not being inside a transaction,
  # and not grabbing Ecto's migration-level advisory lock (it would
  # serialize with the DDL command we're about to issue).
  @disable_ddl_transaction true
  @disable_migration_lock true

  @old_idx :grid_tasks_queued_idx

  # Rust's `claim_next` (rust/prop_grid_rs/src/db.rs) orders by
  # `run_time DESC, forecast_hour ASC` inside the claimable subset
  # (`status='queued' AND forecast_hour > 0 AND kind='forecast'`).
  # The old partial index only indexed `status` — Postgres then had to
  # sort the whole queued tail on every claim. The table is small today
  # (~19 rows/hour, pruned), but ordering inside the index is free to
  # add and future-proofs the worker if we ever expand forecast coverage.
  def change do
    execute(
      """
      CREATE INDEX CONCURRENTLY IF NOT EXISTS grid_tasks_forecast_claim_idx
      ON grid_tasks (run_time DESC, forecast_hour ASC)
      WHERE status = 'queued' AND forecast_hour > 0 AND kind = 'forecast'
      """,
      "DROP INDEX IF EXISTS grid_tasks_forecast_claim_idx"
    )

    # Redundant once the covering partial index exists.
    drop_if_exists(index(:grid_tasks, [:status], name: @old_idx))
  end
end
