/**
  * @param $consoleCommand SyncCommandBase
  * @param $grooveTicket array
  * @return array
  * @throws ValidationException
  * @internal param array $helpscoutUsers
  */
 private static function retrieveThreadsForGrooveTicket($consoleCommand, $grooveTicket)
 {
     $pageNumber = 1;
     $helpscoutThreads = array();
     $grooveTicketNumber = $grooveTicket['number'];
     do {
         /* @var $grooveMessages array */
         $grooveMessages = $consoleCommand->makeRateLimitedRequest(GROOVE, function () use($consoleCommand, $pageNumber, $grooveTicket) {
             return $consoleCommand->getGrooveClient()->messages()->list(['page' => $pageNumber, 'per_page' => 50, 'ticket_number' => $grooveTicket['number']]);
         });
         foreach ($grooveMessages['messages'] as $grooveMessage) {
             $authorEmailAddress = null;
             try {
                 list($authorEmailAddress, $addressType) = self::extractEmailAddressFromGrooveLink($grooveMessage['links']['author']['href'], 'author');
                 // only agents/users can create private notes in HelpScout
                 // this addresses the Groove issue where agents could forward tickets to customers and customers could leave notes
                 $isPrivateNote = $grooveMessage['note'];
                 if ($customerEmails = explode(',', $consoleCommand->option('customerEmails'))) {
                     foreach ($customerEmails as $customerEmail) {
                         if (strcasecmp($customerEmail, $authorEmailAddress) === 0) {
                             $isPrivateNote = false;
                             break;
                         }
                     }
                 }
                 /* @var $thread AbstractThread */
                 $thread = null;
                 if ($isPrivateNote) {
                     $thread = new Note();
                     $thread->setType('note');
                 } else {
                     $thread = new Customer();
                     $thread->setType('customer');
                 }
                 $thread->setBody($grooveMessage['body']);
                 $datetime = new DateTime($grooveMessage['created_at']);
                 $thread->setCreatedAt($datetime->format('c'));
                 // There is no particular status for a single message in Groove
                 // Assume the status is the same as the ticket's
                 $status = APIHelper::getHelpScoutStatusForGrooveState($grooveTicket['state']);
                 if ($status) {
                     $thread->setStatus($status);
                 } else {
                     $consoleCommand->error("Unknown state provided for Groove ticket #{$grooveTicketNumber}: " . $grooveTicket['state']);
                 }
                 // CreatedBy is a PersonRef - type must be 'user' for messages or notes
                 // Type must be 'customer' for customer threads
                 // Chat or phone types can be either 'user' or 'customer'
                 // 'user' types require an ID field
                 // 'customer' types require either an ID or email
                 $id = null;
                 $personRef = new PersonRef();
                 if (strcasecmp($addressType, 'customer') === 0 && !$isPrivateNote) {
                     /* @var $response Collection */
                     $helpscoutCustomer = $consoleCommand->makeRateLimitedRequest(HELPSCOUT, function () use($consoleCommand, $authorEmailAddress) {
                         return $consoleCommand->getHelpScoutClient()->searchCustomersByEmail($authorEmailAddress);
                     });
                     if ($helpscoutCustomer->getCount() > 0) {
                         /* @var $firstItem \HelpScout\model\Customer */
                         $firstItem = $helpscoutCustomer->getItems()[0];
                         $id = $firstItem->getId();
                     } else {
                         // the customer could be blank - we need to fetch extra details from Groove
                         // perhaps the sync-customers was not run?
                         $consoleCommand->warn('Warning: Could not find HelpScout customer for ' . $authorEmailAddress . " (Groove ticket #{$grooveTicketNumber}). Was sync-customers command run?");
                         try {
                             $grooveCustomer = $consoleCommand->makeRateLimitedRequest(GROOVE, function () use($consoleCommand, $grooveMessage) {
                                 // we need to make a raw curl request because the current version of the
                                 // Groove/Guzzle API client does not support disabling urlencoding in URL parameters
                                 // this is apparently a Groove API requirement
                                 $url = $grooveMessage['links']['author']['href'] . '?access_token=' . config('services.groove.key');
                                 $jsonData = json_decode(file_get_contents($url), true);
                                 return $jsonData['customer'];
                             });
                             list($firstName, $lastName) = APIHelper::extractFirstAndLastNameFromFullName($grooveCustomer['name'], $consoleCommand);
                             $personRef->setFirstName($firstName);
                             $personRef->setLastName($lastName);
                         } catch (Exception $e) {
                             $errorMessage = "Groove customer could not be retrieved for ticket #{$grooveTicketNumber} \"" . $grooveTicket['summary'] . "\"";
                             $consoleCommand->error($errorMessage . ": " . $e->getMessage());
                         }
                     }
                 } else {
                     // person is an agent/user
                     $matchingUser = APIHelper::findMatchingUserWithEmail($authorEmailAddress);
                     if (!$matchingUser) {
                         throw new ValidationException("No corresponding user found for: {$authorEmailAddress} (Groove ticket #{$grooveTicketNumber})");
                     }
                     // set ID only on notes
                     if ($isPrivateNote) {
                         $id = $matchingUser->getId();
                     }
                     $personRef->setFirstName($matchingUser->getFirstName());
                     $personRef->setLastName($matchingUser->getLastName());
                 }
                 $personRef->setType($isPrivateNote ? 'user' : 'customer');
                 $personRef->setEmail($authorEmailAddress);
                 $personRef->setId($id);
                 $thread->setCreatedBy($personRef);
                 // To field
                 if (isset($grooveMessage['links']['recipient'])) {
                     list($recipientEmailAddress, $addressType) = self::extractEmailAddressFromGrooveLink($grooveMessage['links']['recipient']['href'], 'recipient');
                     if ($recipientEmailAddress) {
                         $thread->setToList(array($recipientEmailAddress));
                     }
                 }
                 list($attachments, $failedAttachmentNotes) = self::retrieveAttachmentsForGrooveMessage($consoleCommand, $grooveMessage, $status, $grooveTicket);
                 $thread->setAttachments($attachments);
                 $helpscoutThreads[] = $thread;
                 if (count($failedAttachmentNotes) > 0) {
                     $helpscoutThreads = array_merge($helpscoutThreads, $failedAttachmentNotes);
                 }
             } catch (ApiException $e) {
                 $consoleCommand->error("Failed to create HelpScout thread for Groove message (" . $grooveMessage['href'] . " created by {$authorEmailAddress} at " . $grooveMessage['created_at'] . ", ticket #{$grooveTicketNumber}). Message was: \n" . APIHelper::formatApiExceptionArray($e));
             }
         }
         $pageNumber++;
     } while ($pageNumber < $grooveMessages['meta']['pagination']['total_pages']);
     return $helpscoutThreads;
 }