function createAssignAndStart({ available, claim, start, queue, recover, announce }) {
  let request = null;

  function run(item, { alreadyOwned = false, destination = 'start' } = {}) {
    if (request) return request;
    if (!available()) {
      announce('Today is full—remove an item before assigning this issue.');
      return Promise.resolve('full');
    }
    request = Promise.resolve()
      .then(() => alreadyOwned ? item : claim(item))
      .then(confirmed => {
        const outcome = destination === 'queue' ? queue(confirmed) : start(confirmed);
        if (outcome === 'queued') {
          announce(alreadyOwned ? 'Queued in Today. Keep finding work when ready.' :
            'Assigned and queued in Today. Keep finding work when ready.');
          return outcome;
        }
        if (outcome === 'started') {
          announce(alreadyOwned ? 'Added to Today and ready to work.' :
            'Assigned, added to Today, and ready to work.');
          return outcome;
        }
        if (destination === 'queue') {
          if (outcome === 'sync-unavailable') {
            announce(alreadyOwned ?
              'Saved in Today on this device, but account sync is unavailable. The issue is open so you can recover.' :
              'Assigned and saved in Today on this device, but account sync is unavailable. The issue is open so you can recover.');
          } else {
            announce(alreadyOwned ?
              'Today could not be queued. The issue is open so you can recover.' :
              'Assigned to you, but Today could not be queued. The issue is open so you can recover.');
          }
        } else {
          announce(alreadyOwned ?
            'Today could not start. The issue is open so you can recover.' :
            'Assigned to you, but Today could not start. The issue is open so you can recover.');
        }
        recover(confirmed);
        return 'recovery';
      })
      .finally(() => { request = null; });
    return request;
  }

  return { run };
}

if (typeof module !== 'undefined' && module.exports) module.exports = createAssignAndStart;
