defmodule WhoNeedHelp.Workers.ExpireRequestsTest do
  use WhoNeedHelp.DataCase, async: false

  import WhoNeedHelp.AccountsFixtures

  alias WhoNeedHelp.{Catalog, Help, Repo}
  alias WhoNeedHelp.Help.HelpRequest
  alias WhoNeedHelp.Trust.AuditEvent
  alias WhoNeedHelp.Workers.ExpireRequests

  test "expires an arbitrary backlog without loading it as one result set" do
    category = Catalog.seed_defaults()
    requester = user_fixture(display_name: "Expiration requester")
    scope = user_scope_fixture(requester)

    request_ids =
      for number <- 1..12 do
        {:ok, request} =
          Help.create_request(scope, %{
            "title" => "Expiring medicine request #{number}",
            "description" => "The reserved legal medicine was not collected in time.",
            "pickup_instructions" => "No payment or prescription handling is required.",
            "location_label" => "Central district",
            "latitude" => "50.4501",
            "longitude" => "30.5234",
            "urgency" => "today",
            "location_visibility" => "approximate_public",
            "structured_data" => %{"pickup_status" => "reserved"},
            "expires_at" => DateTime.utc_now(:second) |> DateTime.add(3, :hour),
            "category_id" => category.id,
            "safety_confirmed" => true
          })

        request.id
      end

    past = DateTime.utc_now(:second) |> DateTime.add(-1, :minute)

    Repo.update_all(
      from(request in HelpRequest, where: request.id in ^request_ids),
      set: [expires_at: past]
    )

    :ok = Help.subscribe()
    assert {:ok, %{expired: 12}} = ExpireRequests.perform(%Oban.Job{})

    expired_ids =
      for _ <- 1..12 do
        assert_receive {:request_updated, %HelpRequest{status: :expired} = request}
        request.id
      end

    assert MapSet.new(expired_ids) == MapSet.new(request_ids)

    assert Repo.aggregate(
             from(
               request in HelpRequest,
               where: request.id in ^request_ids and request.status == :expired
             ),
             :count
           ) == 12

    assert Repo.aggregate(
             from(
               event in AuditEvent,
               where:
                 event.action == "request.expired" and
                   event.target_id in ^request_ids
             ),
             :count
           ) == 12

    assert {:ok, %{expired: 0}} = ExpireRequests.perform(%Oban.Job{})
  end
end
