require 'rails_helper'

RSpec.describe PostBulkCreator do
  it 'limits workers to two and keeps failures in their request slots' do
    actor = instance_double(User, id: 123)
    allow(User).to receive(:find).with(123) {
      instance_double(User, id: 123)
    }
    mutex = Mutex.new
    active = 0
    maximum_active = 0

    allow(PostCreatePreflight).to receive(:new) do |attributes:, **|
      preflight = instance_double(PostCreatePreflight)
      allow(preflight).to receive(:run) do
        mutex.synchronize do
          active += 1
          maximum_active = [maximum_active, active].max
        end
        sleep 0.02
        mutex.synchronize { active -= 1 }
        attributes.symbolize_keys.merge(
            existing_post_id: nil,
            field_warnings: { },
            base_warnings: [])
      end
      preflight
    end
    allow(PostCreator).to receive(:new) do |attributes:, **|
      creator = instance_double(PostCreator)
      if attributes[:title] == 'broken'
        allow(creator).to receive(:create!).and_raise(StandardError, 'broken')
      else
        post = instance_double(Post, id: attributes[:title].delete_prefix('post ').to_i)
        allow(creator).to receive(:create!).and_return(post)
      end
      creator
    end
    posts = [
        { 'title' => 'post 1', 'url' => 'https://example.com/1' },
        { 'title' => 'broken', 'url' => 'https://example.com/2' },
        { 'title' => 'post 3', 'url' => 'https://example.com/3' },
        { 'title' => 'post 4', 'url' => 'https://example.com/4' }]

    results = described_class.new(
        actor:,
        posts:,
        thumbnails: { }).run.fetch(:results)

    expect(maximum_active).to eq(2)
    expect(results.length).to eq(posts.length)
    expect(results.map { _1[:status] }).to eq(
        ['created', 'failed', 'created', 'created'])
    expect(results[0].dig(:post, :id)).to eq(1)
    expect(results[1]).to include(status: 'failed', recoverable: false)
    expect(results[2].dig(:post, :id)).to eq(3)
    expect(results[3].dig(:post, :id)).to eq(4)
  end
end
