defmodule Tarakan.Repo.Migrations.CreateBounties do
  use Ecto.Migration

  def change do
    create table(:bounties) do
      add :public_id, :uuid, null: false, default: fragment("gen_random_uuid()")
      add :sponsor_account_id, references(:accounts), null: false
      add :target_type, :string, null: false
      add :repository_id, references(:repositories)
      add :pattern_key, :string
      add :canonical_finding_id, references(:canonical_findings)
      add :title, :string, null: false
      add :description, :string, null: false
      add :funding, :string, null: false
      add :amount_cents, :integer
      add :credit_amount, :integer
      add :take_rate, :decimal, precision: 4, scale: 3, null: false
      add :status, :string, null: false, default: "pending_funding"
      add :stripe_checkout_session_id, :string
      add :winner_account_id, references(:accounts)
      add :expires_at, :utc_datetime_usec

      timestamps(type: :utc_datetime_usec)
    end

    create unique_index(:bounties, [:public_id])
    create index(:bounties, [:status])
    create index(:bounties, [:repository_id])
    create index(:bounties, [:pattern_key])
    create index(:bounties, [:canonical_finding_id])
    create index(:bounties, [:sponsor_account_id])
    create index(:bounties, [:stripe_checkout_session_id])

    # Target shape (exactly one ref matching target_type) is validated in the
    # Bounty changeset; see Tarakan.Market.Bounty.validate_target/1.
    create constraint(:bounties, :bounties_target_type_must_be_valid,
             check: "target_type IN ('repository','infestation','finding')"
           )

    create constraint(:bounties, :bounties_funding_must_be_valid,
             check: "funding IN ('fiat','credits')"
           )

    create constraint(:bounties, :bounties_status_must_be_valid,
             check:
               "status IN ('pending_funding','open','claimed','fulfilled','payout_pending','paid','cancelled','expired')"
           )

    create table(:bounty_claims) do
      add :bounty_id, references(:bounties), null: false
      add :account_id, references(:accounts), null: false
      add :review_task_id, references(:review_tasks)
      add :status, :string, null: false, default: "claimed"

      timestamps(type: :utc_datetime_usec)
    end

    create index(:bounty_claims, [:bounty_id])
    create index(:bounty_claims, [:account_id])

    create constraint(:bounty_claims, :bounty_claims_status_must_be_valid,
             check: "status IN ('claimed','submitted','accepted','rejected','withdrawn')"
           )

    # One active claim per hunter per bounty.
    create unique_index(:bounty_claims, [:bounty_id, :account_id],
             name: :bounty_claims_active_unique_index,
             where: "status IN ('claimed','submitted')"
           )
  end
end
