text: <?php
  
  namespace Biz\WeChatNotification\Event;
  
  use AppBundle\Common\ArrayToolkit;
  use AppBundle\Component\Notification\WeChatTemplateMessage\TemplateUtil;
  use Biz\Activity\Service\ActivityService;
  use Biz\AppLoggerConstant;
  use Biz\Classroom\Service\ClassroomService;
  use Biz\Course\Service\CourseService;
  use Biz\Course\Service\CourseSetService;
  use Biz\Course\Service\MemberService;
  use Biz\Course\Service\ThreadService;
  use Biz\System\Service\LogService;
  use Biz\System\Service\SettingService;
  use Biz\Task\Service\TaskService;
  use Biz\User\Service\UserService;
  use Biz\Util\TextHelper;
  use Biz\WeChat\Service\WeChatService;
  use Codeages\Biz\Framework\Event\Event;
  use Codeages\Biz\Framework\Queue\Service\QueueService;
  use Codeages\Biz\Framework\Scheduler\Service\SchedulerService;
  use Codeages\Biz\ItemBank\Answer\Service\AnswerRecordService;
  use Codeages\Biz\ItemBank\Assessment\Service\AssessmentService;
  use Codeages\Biz\Order\Service\OrderService;
  use Codeages\PluginBundle\Event\EventSubscriber;
  use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  
  class WeChatNotificationEventSubscriber extends EventSubscriber implements EventSubscriberInterface
  {
      private $testpaperStatus = ['excellent' => '优秀', 'good' => '良好', 'passed' => '合格', 'unpassed' => '不合格'];
  
      /**
       * @return mixed
       */
      public static function getSubscribedEvents()
      {
          return [
              'course.task.unpublish' => 'onTaskUnpublish',
              'course.task.publish' => 'onTaskPublish',
              'course.task.update' => 'onTaskUpdate',
              'course.task.delete' => 'onTaskDelete',
              'answer.finished' => 'onAnswerFinished',
              'payment_trade.paid' => 'onPaid',
              'course.task.create.sync' => 'onTaskCreateSync',
              'course.task.update.sync' => 'onTaskUpdateSync',
              'course.task.publish.sync' => 'onTaskPublishSync',
              'course.thread.create' => 'onCourseQuestionCreate',
              'thread.create' => 'onClassroomQuestionCreate',
              'course.thread.post.create' => 'onCourseQuestionAnswerCreate',
              'thread.post.create' => 'onClassroomQuestionAnswerCreate',
              'wechat.template_setting.save' => 'onWeChatTemplateSettingSave',
          ];
      }
  
      public function onTaskUnpublish(Event $event)
      {
          $task = $event->getSubject();
          $this->deleteLiveNotificationJob($task);
      }
  
      public function onTaskPublish(Event $event)
      {
          $task = $event->getSubject();
          $course = $this->getCourseService()->getCourse($task['courseId']);
          $courseSet = $this->getCourseSetService()->getCourseSet($course['courseSetId']);
          if ('published' != $courseSet['status'] || 'published' != $course['status']) {
              return;
          }
  
          $this->sendTasksPublishNotification([$task]);
      }
  
      public function onTaskUpdate(Event $event)
      {
          $task = $event->getSubject();
          if ('live' == $task['type']) {
              $this->deleteLiveNotificationJob($task);
  
              if ('published' == $task['status']) {
                  $this->registerLiveNotificationJob($task);
              }
          }
      }
  
      public function onTaskDelete(Event $event)
      {
          $task = $event->getSubject();
          $this->deleteLiveNotificationJob($task);
      }
  
      public function onAnswerFinished(Event $event)
      {
          $answerReport = $event->getSubject();
          $answerRecord = $this->getAnswerRecordService()->get($answerReport['answer_record_id']);
          $activity = $this->getActivityService()->getActivityByAnswerSceneId($answerReport['answer_scene_id']);
          if (empty($activity)) {
              return;
          }
          $task = $this->getTaskService()->getTaskByCourseIdAndActivityId($activity['fromCourseId'], $activity['id']);
          $assessment = $this->getAssessmentService()->getAssessment($answerRecord['assessment_id']);
          if (empty($task)) {
              $this->getLogService()->error(AppLoggerConstant::NOTIFY, 'wechat_notification_error', '发送微信通知失败:获取任务失败', $paperResult);
  
              return;
          }
  
          if (!in_array($activity['mediaType'], ['testpaper', 'homework'])) {
              return;
          }
  
          if ('testpaper' == $activity['mediaType']) {
              $key = 'examResult';
              $logName = 'wechat_notify_exam_result';
              $data = [
                  'first' => ['value' => '同学，您好，您的试卷已批阅完成'],
                  'keyword1' => ['value' => $task['title']],
                  'keyword2' => ['value' => $answerReport['score']],
                  'remark' => ['value' => '再接再厉哦'],
              ];
          } elseif ('homework' == $activity['mediaType']) {
              $key = 'homeworkResult';
              $logName = 'wechat_notify_homework_result';
              $course = $this->getCourseService()->getCourse($task['courseId']);
              $teachers = $this->getCourseMemberService()->searchMembers(
                  ['courseId' => $course['id'], 'role' => 'teacher', 'isVisible' => 1],
                  ['id' => 'asc'],
                  0,
                  1
              );
              if (empty($teachers)) {
                  $nickname = '';
              } else {
                  $user = $this->getUserService()->getUser($teachers[0]['userId']);
                  $nickname = $user['nickname'];
              }
  
              $data = [
                  'first' => ['value' => '同学，您好，您的作业已批阅完成'],
                  'keyword1' => ['value' => $task['title']],
                  'keyword2' => ['value' => $course['courseSetTitle']],
                  'keyword3' => ['value' => $nickname],
                  'remark' => ['value' => '作业结果：'.$this->testpaperStatus[$answerReport['grade']]],
              ];
          }
  
          $templateId = $this->getWeChatService()->getTemplateId($key);
          if (empty($templateId)) {
              return;
          }
  
          $options = ['type' => 'url', 'url' => $this->generateUrl('course_task_show', ['courseId' => $task['courseId'], 'id' => $task['id']], UrlGeneratorInterface::ABSOLUTE_URL)];
          $weChatUser = $this->getWeChatService()->getOfficialWeChatUserByUserId($answerRecord['user_id']);
          if (empty($weChatUser['isSubscribe']) || $this->isUserLocked($answerRecord['user_id'])) {
              return;
          }
  
          $templates = TemplateUtil::templates();
          $templateCode = isset($templates[$key]['id']) ? $templates[$key]['id'] : '';
          $list = [[
              'channel' => $this->getWeChatService()->getWeChatSendChannel(),
              'to_id' => $weChatUser['openId'],
              'template_id' => $templateId,
              'template_code' => $templateCode,
              'template_args' => $data,
              'goto' => $options,
          ]];
          $this->sendCloudWeChatNotification($key, $logName, $list);
      }
  
      public function onPaid(Event $event)
      {
          $trade = $event->getSubject();
          $chargeTemplateId = $this->getWeChatService()->getTemplateId('coinRecharge');
          $payTemplateId = $this->getWeChatService()->getTemplateId('paySuccess');
          if (!empty($chargeTemplateId) && 'recharge' == $trade['type']) {
              $data = [
                  'first' => ['value' => '尊敬的客户，您已充值成功'],
                  'keyword1' => ['value' => '现金充值'],
                  'keyword2' => ['value' => $trade['trade_sn']],
                  'keyword3' => ['value' => ($trade['amount'] / 100).'元'],
                  'keyword4' => ['value' => date('Y-m-d H:i', $trade['pay_time'])],
                  'remark' => ['value' => '快去看看课程吧~'],
              ];
              $options = ['type' => 'url', 'url' => $this->generateUrl('course_set_explore', [], UrlGeneratorInterface::ABSOLUTE_URL)];
              $weChatUser = $this->getWeChatService()->getOfficialWeChatUserByUserId($trade['user_id']);
              $templates = TemplateUtil::templates();
              $templateCode = isset($templates['coinRecharge']['id']) ? $templates['coinRecharge']['id'] : '';
              if (!empty($weChatUser['isSubscribe']) && !$this->isUserLocked($trade['user_id'])) {
                  $list = [[
                      'channel' => $this->getWeChatService()->getWeChatSendChannel(),
                      'to_id' => $weChatUser['openId'],
                      'template_id' => $chargeTemplateId,
                      'template_code' => $templateCode,
                      'template_args' => $data,
                      'goto' => $options,
                  ]];
                  $this->sendCloudWeChatNotification('coinRecharge', 'wechat_notify_coin_recharge', $list);
              }
          }
  
          if (!empty($payTemplateId)) {
              $data = [
                  'first' => ['value' => '尊敬的客户，您已支付成功'],
                  'keyword1' => ['value' => $trade['title']],
                  'keyword2' => ['value' => ($trade['amount'] / 100).'元'],
                  'keyword3' => ['value' => date('Y-m-d H:i', $trade['pay_time'])],
                  'keyword4' => ['value' => '无'],
                  'remark' => ['value' => '请前往查看'],
              ];
              $order = $this->getOrderService()->getOrderBySn($trade['order_sn']);
              if (empty($order)) {
                  return;
              }
              $orderItems = $this->getOrderService()->findOrderItemsByOrderId($order['id']);
              $options = ['type' => 'url', 'url' => $this->getOrderTargetDetailUrl($orderItems[0]['target_type'], $orderItems[0]['target_id'])];
              $weChatUser = empty($weChatUser) ? $this->getWeChatService()->getOfficialWeChatUserByUserId($trade['user_id']) : $weChatUser;
              $templates = TemplateUtil::templates();
              $templateCode = isset($templates['paySuccess']['id']) ? $templates['paySuccess']['id'] : '';
              if (!empty($weChatUser['isSubscribe']) && !$this->isUserLocked($trade['user_id'])) {
                  $list = [[
                      'channel' => $this->getWeChatService()->getWeChatSendChannel(),
                      'to_id' => $weChatUser['openId'],
                      'template_id' => $payTemplateId,
                      'template_code' => $templateCode,
                      'template_args' => $data,
                      'goto' => $options,
                  ]];
                  $this->sendCloudWeChatNotification('paySuccess', 'wechat_notify_pay_success', $list);
              }
          }
      }
  
      public function onTaskCreateSync(Event $event)
      {
          $task = $event->getSubject();
  
          if ('published' == $task['status']) {
              $tasks = $this->getCopiedTasks($task);
  
              $this->sendTasksPublishNotification($tasks);
          }
      }
  
      public function onTaskUpdateSync(Event $event)
      {
          $task = $event->getSubject();
          if ('live' == $task['type']) {
              $copiedTasks = $this->getCopiedTasks($task);
              foreach ($copiedTasks as $copiedTask) {
                  $this->deleteLiveNotificationJob($copiedTask);
                  if ('published' == $copiedTask['status']) {
                      $this->registerLiveNotificationJob($copiedTask);
                  }
              }
          }
      }
  
      public function onTaskPublishSync(Event $event)
      {
          $task = $event->getSubject();
  
          if ('published' == $task['status'] && $this->isTaskCreateSyncFinished($task)) {
              $tasks = $this->getCopiedTasks($task);
  
              $this->sendTasksPublishNotification($tasks);
          }
      }
  
      public function onCourseQuestionCreate(Event $event)
      {
          $thread = $event->getSubject();
          if ('question' != $thread['type']) {
              return;
          }
          $course = $this->getCourseService()->getCourse($thread['courseId']);
          $teachers = $this->getCourseMemberService()->findCourseTeachers($course['id']);
          $userIds = ArrayToolkit::column($teachers, 'userId');
  
          if (empty($userIds)) {
              return;
          }
  
          $courseName = empty($course['title']) ? $course['courseSetTitle'] : $course['title'];
  
          $templateParams = [
              'thread' => $thread,
              'userIds' => $userIds,
              'title' => "在教课程《{$courseName}》",
              'goto' => $this->generateUrl('course_thread_show', ['courseId' => $course['id'], 'threadId' => $thread['id']], UrlGeneratorInterface::ABSOLUTE_URL),
          ];
          $this->askQuestionSendNotification($templateParams);
      }
  
      public function onClassroomQuestionCreate(Event $event)
      {
          $thread = $event->getSubject();
  
          if ('classroom' != $thread['targetType'] || 'question' != $thread['type']) {
              return;
          }
          $classroom = $this->getClassroomService()->getClassroom($thread['targetId']);
          $userIds = $this->getClassroomService()->findTeachers($classroom['id']);
          if (empty($userIds)) {
              return;
          }
  
          $templateParams = [
              'thread' => $thread,
              'userIds' => $userIds,
              'title' => "在教班级《{$classroom['title']}》",
              'goto' => $this->generateUrl('classroom_thread_show', ['classroomId' => $classroom['id'], 'threadId' => $thread['id']], UrlGeneratorInterface::ABSOLUTE_URL),
          ];
  
          $this->askQuestionSendNotification($templateParams);
      }
  
      public function onCourseQuestionAnswerCreate(Event $event)
      {
          $post = $event->getSubject();
  
          if (empty($post['courseId'])) {
              return;
          }
  
          $course = $this->getCourseService()->getCourse($post['courseId']);
          $thread = $this->getCourseThreadService()->getThread($course['id'], $post['threadId']);
          if ($this->getCourseMemberService()->isCourseTeacher($post['courseId'], $post['userId'])) {
              $title = empty($course['title']) ? $course['courseSetTitle'] : $course['title'];
              if (!$this->isUserLocked($thread['userId'])) {
                  $templateParams = [
                      'userId' => $thread['userId'],
                      'content' => $post['content'],
                      'title' => $title,
                      'createdTime' => $thread['createdTime'],
                      'goto' => $this->generateUrl('course_thread_show', ['courseId' => $course['id'], 'threadId' => $thread['id']], UrlGeneratorInterface::ABSOLUTE_URL),
                  ];
                  $this->answerQuestionNotification($templateParams);
              }
          }
      }
  
      public function onClassroomQuestionAnswerCreate(Event $event)
      {
          $post = $event->getSubject();
  
          if (empty($post['targetId']) && 'classroom' != $post['targetType']) {
              return;
          }
  
          $classroom = $this->getClassroomService()->getClassroom($post['targetId']);
          $thread = $this->getThreadService()->getThread($post['threadId']);
  
          if ($this->getClassroomService()->isClassroomTeacher($post['targetId'], $post['userId'])) {
              if (!$this->isUserLocked($thread['userId'])) {
                  $templateParams = [
                      'userId' => $thread['userId'],
                      'content' => $post['content'],
                      'title' => $classroom['title'],
                      'createdTime' => $thread['createdTime'],
                      'goto' => $this->generateUrl('classroom_thread_show', ['classroomId' => $classroom['id'], 'threadId' => $thread['id']], UrlGeneratorInterface::ABSOLUTE_URL),
                  ];
                  $this->answerQuestionNotification($templateParams);
              }
          }
      }
  
      public function onWeChatTemplateSettingSave(Event $event)
      {
          $fields = $event->getSubject();
          $key = $event->getArgument('key');
          $wechatSetting = $this->getSettingService()->get('wechat', []);
          $templates = empty($wechatSetting['templates']) ? [] : $wechatSetting['templates'];
          if ('homeworkOrTestPaperReview' == $key) {
              $templates['homeworkOrTestPaperReview']['sendTime'] = $fields['sendTime'];
              $notificationJob = $this->getSchedulerService()->getJobByName('WeChatNotificationJob_HomeWorkOrTestPaperReview');
              if ($notificationJob) {
                  $this->getSchedulerService()->deleteJob($notificationJob['id']);
              }
              if (!empty($templates['homeworkOrTestPaperReview']['templateId']) && !empty($templates['homeworkOrTestPaperReview']['sendTime'])) {
                  $expression = $this->getSendTimeExpression($fields['sendTime']);
  
                  if (1 == $templates['homeworkOrTestPaperReview']['status']) {
                      $job = [
                          'name' => 'WeChatNotificationJob_HomeWorkOrTestPaperReview',
                          'expression' => $expression,
                          'class' => 'Biz\WeChatNotification\Job\HomeWorkOrTestPaperReviewNotificationJob',
                          'misfire_policy' => 'executing',
                          'args' => [
                              'key' => $key,
                              'sendTime' => $templates['homeworkOrTestPaperReview']['sendTime'],
                          ],
                      ];
                      $this->getSchedulerService()->register($job);
                  }
              }
          }
  
          if ('courseRemind' == $key) {
              $templates['courseRemind']['sendTime'] = $fields['sendTime'];
              $templates['courseRemind']['sendDays'] = empty($fields['sendDays']) ? [] : $fields['sendDays'];
              $notificationJob = $this->getSchedulerService()->getJobByName('WeChatNotificationJob_CourseRemind');
              if ($notificationJob) {
                  $this->getSchedulerService()->deleteJob($notificationJob['id']);
              }
              if (!empty($templates['courseRemind']['templateId']) && !empty($templates['courseRemind']['sendTime']) && !empty($templates['courseRemind']['sendDays'])) {
                  $expression = $this->getSendDayAndTimeExpression($templates['courseRemind']['sendDays'], $templates['courseRemind']['sendTime']);
  
                  if (1 == $templates['courseRemind']['status']) {
                      $job = [
                          'name' => 'WeChatNotificationJob_CourseRemind',
                          'expression' => $expression,
                          'class' => 'Biz\WeChatNotification\Job\CourseRemindNotificationJob',
                          'misfire_policy' => 'executing',
                          'args' => [
                              'key' => $key,
                              'url' => $this->generateUrl('my_courses_learning', [], UrlGeneratorInterface::ABSOLUTE_URL),
                              'sendTime' => $templates['courseRemind']['sendTime'],
                              'sendDays' => $templates['courseRemind']['sendDays'],
                          ],
                      ];
                      $this->getSchedulerService()->register($job);
                  }
              }
          }
      }
  
      protected function answerQuestionNotification($templateParams)
      {
          $templateParams = ArrayToolkit::filter($templateParams, [
              'userId' => null,
              'content' => null,
              'title' => null,
              'createdTime' => null,
              'goto' => null,
          ]);
  
          $templateId = $this->getWeChatService()->getTemplateId('answerQuestion');
          if (!empty($templateId)) {
              $weChatUser = $this->getWeChatService()->getOfficialWeChatUserByUserId($templateParams['userId']);
  
              if (empty($weChatUser)) {
                  return;
              }
              $content = TextHelper::truncate($templateParams['content'], 30);
              $data = [
                  'first' => ['value' => '亲爱的学员，您在《'.$templateParams['title'].'》中的发表的问题有了新的回答'],
                  'keyword1' => ['value' => date('Y-m-d H:i:s', $templateParams['createdTime'])],
                  'keyword2' => ['value' => $content],
                  'remark' => ['value' => ''],
              ];
  
              $templates = TemplateUtil::templates();
              $templateCode = isset($templates['answerQuestion']['id']) ? $templates['answerQuestion']['id'] : '';
              $list = [[
                  'channel' => $this->getWeChatService()->getWeChatSendChannel(),
                  'to_id' => $weChatUser['openId'],
                  'template_id' => $templateId,
                  'template_code' => $templateCode,
                  'template_args' => $data,
                  'goto' => [
                      'type' => 'url',
                      'url' => $templateParams['goto'],
                  ],
              ]];
  
              $this->sendCloudWeChatNotification('answerQuestion', 'wechat_notify_answer_question', $list);
          }
      }
  
      protected function askQuestionSendNotification($templateParams)
      {
          $templateParams = ArrayToolkit::filter($templateParams, [
              'thread' => [],
              'userIds' => [],
              'title' => null,
              'goto' => null,
          ]);
  
          $users = $this->getUserService()->searchUsers(
              ['userIds' => $templateParams['userIds'], 'locked' => 0],
              [],
              0,
              PHP_INT_MAX
          );
          $userIds = ArrayToolkit::column($users, 'id');
  
          if (empty($userIds)) {
              return;
          }
          $templateId = $this->getWeChatService()->getTemplateId('askQuestion');
          if (!empty($templateId)) {
              $user = $this->getUserService()->getUser($templateParams['thread']['userId']);
              $weChatUsers = $this->getWeChatService()->searchWeChatUsers(
                  ['userIds' => $userIds],
                  ['lastRefreshTime' => 'ASC'],
                  0,
                  PHP_INT_MAX,
                  ['id', 'openId', 'unionId', 'userId']
              );
  
              if (empty($weChatUsers)) {
                  return;
              }
  
              $data = [
                  'first' => ['value' => '尊敬的老师，您的'.$templateParams['title'].'中有学员发布了提问'],
                  'keyword1' => ['value' => $user['nickname']],
                  'keyword2' => ['value' => mb_substr($templateParams['thread']['title'], 0, 30, 'utf-8')],
                  'keyword3' => ['value' => date('Y-m-d H:i:s', $templateParams['thread']['createdTime'])],
                  'remark' => ['value' => ''],
              ];
              $templates = TemplateUtil::templates();
              $templateCode = isset($templates['askQuestion']['id']) ? $templates['askQuestion']['id'] : '';
              $templateData = [
                  'template_id' => $templateId,
                  'template_code' => $templateCode,
                  'template_args' => $data,
              ];
  
              $list = [];
              foreach ($weChatUsers as $weChatUser) {
                  $list[] = array_merge([
                      'channel' => $this->getWeChatService()->getWeChatSendChannel(),
                      'to_id' => $weChatUser['openId'],
                      'goto' => [
                          'type' => 'url',
                          'url' => $templateParams['goto'],
                      ],
                  ], $templateData);
              }
  
              $this->sendCloudWeChatNotification('askQuestion', 'wechat_notify_ask_question', $list);
          }
      }
  
      protected function sendCloudWeChatNotification($key, $logName, $list)
      {
          try {
              $result = $this->getCloudNotificationClient()->sendNotifications($list);
          } catch (\Exception $e) {
              $this->getLogService()->error(AppLoggerConstant::NOTIFY, $logName, "发送微信通知失败:template:{$key}", ['error' => $e->getMessage()]);
  
              return;
          }
  
          if (empty($result['sn'])) {
              $this->getLogService()->error(AppLoggerConstant::NOTIFY, $logName, "发送微信通知失败:template:{$key}", $result);
  
              return;
          }
  
          $this->getNotificationService()->createWeChatNotificationRecord($result['sn'], $key, $list[0]['template_args']);
      }
  
      protected function sendTasksPublishNotification($tasks)
      {
          foreach ($tasks as $task) {
              if ('live' == $task['type']) {
                  $this->deleteLiveNotificationJob($task);
                  $this->registerLiveNotificationJob($task);
              }
              $key = TemplateUtil::TEMPLATE_COURSE_UPDATE;
              $this->deleteLessonPublishJob($task);
              $this->registerLessonNotificationJob($key, $task);
          }
      }
  
      private function getOrderTargetDetailUrl($targetType, $targetId)
      {
          switch ($targetType) {
              case 'course':
                  return $this->generateUrl('my_course_show', ['id' => $targetId], UrlGeneratorInterface::ABSOLUTE_URL);
  
              case 'classroom':
                  return $this->generateUrl('classroom_show', ['id' => $targetId], UrlGeneratorInterface::ABSOLUTE_URL);
  
              case 'vip':
                  return $this->generateUrl('vip', [], UrlGeneratorInterface::ABSOLUTE_URL);
  
              default:
                  return '';
          }
      }
  
      private function registerLessonNotificationJob($key, $task)
      {
          $templateId = $this->getWeChatService()->getTemplateId($key);
          if (!empty($templateId)) {
              $job = [
                  'name' => 'WeChatNotificationJob_LessonPublish_'.$task['id'],
                  'expression' => time(),
                  'class' => 'Biz\WeChatNotification\Job\LessonPublishNotificationJob',
                  'misfire_threshold' => 60 * 60,
                  'args' => [
                      'key' => $key,
                      'taskId' => $task['id'],
                      'url' => $this->generateUrl('my_course_show', ['id' => $task['courseId']], UrlGeneratorInterface::ABSOLUTE_URL),
                  ],
              ];
              $this->getSchedulerService()->register($job);
          }
      }
  
      private function registerLiveNotificationJob($task)
      {
          $hourTemplateId = $this->getWeChatService()->getTemplateId(TemplateUtil::TEMPLATE_LIVE_OPEN, 'beforeOneHour');
          $dayTemplateId = $this->getWeChatService()->getTemplateId(TemplateUtil::TEMPLATE_LIVE_OPEN, 'beforeOneDay');
          if (!empty($dayTemplateId) && $task['startTime'] >= (time() + 24 * 60 * 60)) {
              $job = [
                  'name' => 'WeChatNotificationJob_LiveOneDay_'.$task['id'],
                  'expression' => intval($task['startTime'] - 24 * 60 * 60),
                  'class' => 'Biz\WeChatNotification\Job\LiveNotificationJob',
                  'misfire_threshold' => 60 * 60,
                  'args' => [
                      'key' => 'liveOpen',
                      'taskId' => $task['id'],
                      'url' => $this->generateUrl('my_course_show', ['id' => $task['courseId']], UrlGeneratorInterface::ABSOLUTE_URL),
                  ],
              ];
              $this->getSchedulerService()->register($job);
          }
  
          if (!empty($hourTemplateId) && $task['startTime'] >= (time() + 60 * 60)) {
              $job = [
                  'name' => 'WeChatNotificationJob_LiveOneHour_'.$task['id'],
                  'expression' => intval($task['startTime'] - 60 * 60),
                  'class' => 'Biz\WeChatNotification\Job\LiveNotificationJob',
                  'misfire_threshold' => 60 * 10,
                  'args' => [
                      'key' => 'liveOpen',
                      'taskId' => $task['id'],
                      'url' => $this->generateUrl('my_course_show', ['id' => $task['courseId']], UrlGeneratorInterface::ABSOLUTE_URL),
                  ],
              ];
              $this->getSchedulerService()->register($job);
          }
      }
  
      private function getCopiedTasks($task)
      {
          if (empty($task)) {
              return [];
          }
  
          $courses = $this->getCourseService()->findCoursesByParentIdAndLocked($task['courseId'], 1);
  
          return $this->getTaskDao()->findByCopyIdAndLockedCourseIds($task['id'], ArrayToolkit::column($courses, 'id'));
      }
  
      private function isTaskCreateSyncFinished($task)
      {
          $courses = $this->getCourseService()->findCoursesByParentIdAndLocked($task['courseId'], 1);
          $tasks = $this->getTaskDao()->findByCopyIdAndLockedCourseIds($task['id'], ArrayToolkit::column($courses, 'id'));
  
          if (count($tasks) == count($courses)) {
              return true;
          }
  
          return false;
      }
  
      protected function getSendDayAndTimeExpression($days, $time)
      {
          $filterDays = [];
  
          $allDays = [
              'Sun' => 0,
              'Mon' => 1,
              'Tue' => 2,
              'Wed' => 3,
              'Thu' => 4,
              'Fri' => 5,
              'Sat' => 6,
          ];
  
          foreach ($allDays as $key => $day) {
              if (in_array($key, $days)) {
                  $filterDays[] = $day;
              }
          }
  
          $runDays = implode(',', $filterDays);
          $runDays = empty($runDays) ? '*' : $runDays;
          $time = explode(':', $time);
          $hour = 2 === count($time) ? $time[0] : 0;
          $minute = 2 === count($time) ? $time[1] : 0;
  
          return $minute.' '.$hour.' * * '.$runDays;
      }
  
      protected function getSendTimeExpression($sendTime)
      {
          $expression = '';
          if (!is_array($sendTime)) {
              $hourAndMinute = explode(':', $sendTime);
              $minute = ($hourAndMinute[1] < 10) ? $hourAndMinute[1] % 10 : $hourAndMinute[1];
              $hour = ($hourAndMinute[0] < 10) ? $hourAndMinute[0] % 10 : $hourAndMinute[0];
  
              $expression = $minute.' '.$hour.' * * *';
          }
  
          return $expression;
      }
  
      protected function isUserLocked($userId)
      {
          $user = $this->getUserService()->getUser($userId);
  
          if ($user['locked']) {
              return true;
          }
  
          return false;
      }
  
      private function deleteLessonPublishJob($task)
      {
          $this->deleteByJobName('WeChatNotificationJob_LessonPublish_'.$task['id']);
      }
  
      private function deleteLiveNotificationJob($task)
      {
          $this->deleteByJobName('WeChatNotificationJob_LiveOneHour_'.$task['id']);
          $this->deleteByJobName('WeChatNotificationJob_LiveOneDay_'.$task['id']);
      }
  
      private function deleteByJobName($jobName)
      {
          $jobs = $this->getSchedulerService()->searchJobs(['name' => $jobName], [], 0, PHP_INT_MAX);
  
          foreach ($jobs as $job) {
              $this->getSchedulerService()->deleteJob($job['id']);
          }
      }
  
      /**
       * @param $route
       * @param $parameters
       * @param $referenceType
       *
       * @return mixed
       */
      private function generateUrl($route, $parameters, $referenceType = UrlGeneratorInterface::ABSOLUTE_URL)
      {
          global $kernel;
          $router = $this->decorateRouter($kernel->getContainer()->get('router'));
  
          return $router->generate($route, $parameters, $referenceType);
      }
  
      private function decorateRouter($router)
      {
          $routerContext = $router->getContext();
          if ('localhost' == $routerContext->getHost()) {
              $url = $this->getSettingService()->node('site.url');
              if (!empty($url)) {
                  $parsedUrl = parse_url($url);
  
                  empty($parsedUrl['host']) ?: $routerContext->setHost($parsedUrl['host']);
                  empty($parsedUrl['scheme']) ?: $routerContext->setScheme($parsedUrl['scheme']);
              }
          }
  
          return $router;
      }
  
      private function getCloudNotificationClient()
      {
          $biz = $this->getBiz();
  
          return $biz['qiQiuYunSdk.notification'];
      }
  
      /**
       * @return CourseService
       */
      protected function getCourseService()
      {
          return $this->getBiz()->service('Course:CourseService');
      }
  
      /**
       * @return QueueService
       */
      protected function getQueueService()
      {
          return $this->getBiz()->service('Queue:QueueService');
      }
  
      /**
       * @return SchedulerService
       */
      private function getSchedulerService()
      {
          return $this->getBiz()->service('Scheduler:SchedulerService');
      }
  
      /**
       * @return TaskService
       */
      protected function getTaskService()
      {
          return $this->getBiz()->service('Task:TaskService');
      }
  
      /**
       * @return CourseSetService
       */
      protected function getCourseSetService()
      {
          return $this->getBiz()->service('Course:CourseSetService');
      }
  
      /**
       * @return MemberService
       */
      protected function getCourseMemberService()
      {
          return $this->getBiz()->service('Course:MemberService');
      }
  
      /**
       * @return UserService
       */
      protected function getUserService()
      {
          return $this->getBiz()->service('User:UserService');
      }
  
      /**
       * @return WeChatService
       */
      protected function getWeChatService()
      {
          return $this->getBiz()->service('WeChat:WeChatService');
      }
  
      /**
       * @return OrderService
       */
      protected function getOrderService()
      {
          return $this->getBiz()->service('Order:OrderService');
      }
  
      /**
       * @return LogService
       */
      protected function getLogService()
      {
          return $this->getBiz()->service('System:LogService');
      }
  
      protected function getNotificationService()
      {
          return $this->getBiz()->service('Notification:NotificationService');
      }
  
      /**
       * @return ActivityService
       */
      protected function getActivityService()
      {
          return $this->getBiz()->service('Activity:ActivityService');
      }
  
      protected function getTaskDao()
      {
          return $this->getBiz()->dao('Task:TaskDao');
      }
  
      /**
       * @return ClassroomService
       */
      protected function getClassroomService()
      {
          return $this->getBiz()->service('Classroom:ClassroomService');
      }
  
      /**
       * @return ThreadService
       */
      protected function getCourseThreadService()
      {
          return $this->getBiz()->service('Course:ThreadService');
      }
  
      /**
       * @return \Biz\Thread\Service\ThreadService
       */
      protected function getThreadService()
      {
          return $this->getBiz()->service('Thread:ThreadService');
      }
  
      /**
       * @return SettingService
       */
      protected function getSettingService()
      {
          return $this->getBiz()->service('System:SettingService');
      }
  
      /**
       * @return AnswerRecordService
       */
      public function getAnswerRecordService()
      {
          return $this->getBiz()->service('ItemBank:Answer:AnswerRecordService');
      }
  
      /**
       * @return AssessmentService
       */
      public function getAssessmentService()
      {
          return $this->getBiz()->service('ItemBank:Assessment:AssessmentService');
      }
  }
  