# frozen_string_literal: true

#
# Copyright (C) 2015 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.

module Canvas::LiveEvents
  def self.post_event_stringified(event_name, payload, context = nil)
    ctx = LiveEvents.get_context || {}
    payload.compact! if ctx.dig(:compact_live_events)&.present?

    StringifyIds.recursively_stringify_ids(payload)
    StringifyIds.recursively_stringify_ids(context)
    LiveEvents.post_event(
      event_name: event_name,
      payload: payload,
      time: Time.zone.now,
      context: context
    )
  end

  def self.amended_context(canvas_context)
    ctx = LiveEvents.get_context || {}
    return ctx unless canvas_context
    ctx = ctx.merge({
      context_type: canvas_context.class.to_s,
      context_id: canvas_context.global_id
    })
    if canvas_context.respond_to?(:root_account)
      ctx.merge!({
        root_account_id: canvas_context.root_account.try(:global_id),
        root_account_uuid: canvas_context.root_account.try(:uuid),
        root_account_lti_guid: canvas_context.root_account.try(:lti_guid),
      })
    end
    ctx
  end

  def self.conversation_created(conversation)
    post_event_stringified('conversation_created', {
      conversation_id: conversation.id,
      updated_at: conversation.updated_at
    })
  end

  def self.conversation_forwarded(conversation)
    post_event_stringified('conversation_forwarded', {
      conversation_id: conversation.id,
      updated_at: conversation.updated_at
      },
      amended_context(nil))
  end

  def self.get_course_data(course)
    {
      course_id: course.global_id,
      uuid: course.uuid,
      account_id: course.global_account_id,
      name: course.name,
      created_at: course.created_at,
      updated_at: course.updated_at,
      workflow_state: course.workflow_state
    }
  end

  def self.course_created(course)
    post_event_stringified('course_created', get_course_data(course))
  end

  def self.course_updated(course)
    post_event_stringified('course_updated', get_course_data(course))
  end

  def self.course_syllabus_updated(course, old_syllabus_body)
    post_event_stringified('syllabus_updated', {
      course_id: course.global_id,
      syllabus_body: LiveEvents.truncate(course.syllabus_body),
      old_syllabus_body: LiveEvents.truncate(old_syllabus_body)
    })
  end

  def self.conversation_message_created(conversation_message)
    post_event_stringified('conversation_message_created', {
      author_id: conversation_message.author_id,
      conversation_id: conversation_message.conversation_id,
      created_at: conversation_message.created_at,
      message_id: conversation_message.id
    })
  end

  def self.discussion_entry_created(entry)
    post_event_stringified('discussion_entry_created', get_discussion_entry_data(entry))
  end

  def self.discussion_entry_submitted(entry, assignment_id, submission_id)
    payload = get_discussion_entry_data(entry)
    payload[:assignment_id] = assignment_id unless assignment_id.nil?
    payload[:submission_id] = submission_id unless submission_id.nil?
    post_event_stringified('discussion_entry_submitted', payload)
  end

  def self.get_discussion_entry_data(entry)
    payload = {
      user_id:  entry.user_id,
      created_at: entry.created_at,
      discussion_entry_id: entry.id,
      discussion_topic_id: entry.discussion_topic_id,
      text: LiveEvents.truncate(entry.message)
    }

    payload[:parent_discussion_entry_id] = entry.parent_id if entry.parent_id
    payload
  end

  def self.discussion_topic_created(topic)
    post_event_stringified('discussion_topic_created', get_discussion_topic_data(topic))
  end

  def self.discussion_topic_updated(topic)
    post_event_stringified('discussion_topic_updated', get_discussion_topic_data(topic))
  end

  def self.get_discussion_topic_data(topic)
    {
      discussion_topic_id: topic.global_id,
      is_announcement: topic.is_announcement,
      title: LiveEvents.truncate(topic.title),
      body: LiveEvents.truncate(topic.message),
      assignment_id: topic.assignment_id,
      context_id: topic.context_id,
      context_type: topic.context_type,
      workflow_state: topic.workflow_state,
      lock_at: topic.lock_at,
      updated_at: topic.updated_at
    }
  end

  def self.account_notification_created(notification)
    post_event_stringified('account_notification_created', {
      account_notification_id: notification.global_id,
      subject: LiveEvents.truncate(notification.subject),
      message: LiveEvents.truncate(notification.message),
      icon: notification.icon,
      start_at: notification.start_at,
      end_at: notification.end_at,
    })
  end

  def self.get_group_membership_data(membership)
    {
      group_membership_id: membership.global_id,
      user_id: membership.global_user_id,
      group_id: membership.global_group_id,
      group_name: membership.group.name,
      group_category_id: membership.group.global_group_category_id,
      group_category_name: membership.group.group_category.try(:name),
      workflow_state: membership.workflow_state
    }
  end

  def self.group_membership_created(membership)
    post_event_stringified('group_membership_created', get_group_membership_data(membership))
  end

  def self.group_membership_updated(membership)
    post_event_stringified('group_membership_updated', get_group_membership_data(membership))
  end

  def self.get_group_category_data(group_category)
    {
      group_category_id: group_category.global_id,
      group_category_name: group_category.name,
      context_id: group_category.context_id,
      context_type: group_category.context_type,
      group_limit: group_category.group_limit
    }
  end

  def self.group_category_updated(group_category)
    post_event_stringified('group_category_updated', get_group_category_data(group_category))
  end

  def self.group_category_created(group_category)
    post_event_stringified('group_category_created', get_group_category_data(group_category))
  end

  def self.get_group_data(group)
    {
      group_category_id: group.global_group_category_id,
      group_category_name: group.group_category.try(:name),
      group_id: group.global_id,
      uuid: group.uuid,
      group_name: group.name,
      context_type: group.context_type,
      context_id: group.global_context_id,
      account_id: group.global_account_id,
      workflow_state: group.workflow_state,
      max_membership: group.max_membership
    }
  end

  def self.group_created(group)
    post_event_stringified('group_created', get_group_data(group))
  end

  def self.group_updated(group)
    post_event_stringified('group_updated', get_group_data(group))
  end

  def self.get_assignment_data(assignment)
    event = {
      assignment_id: assignment.global_id,
      context_id: assignment.global_context_id,
      context_uuid: assignment.context.uuid,
      context_type: assignment.context_type,
      assignment_group_id: assignment.global_assignment_group_id,
      workflow_state: assignment.workflow_state,
      title: LiveEvents.truncate(assignment.title),
      description: LiveEvents.truncate(assignment.description),
      due_at: assignment.due_at,
      unlock_at: assignment.unlock_at,
      lock_at: assignment.lock_at,
      updated_at: assignment.updated_at,
      points_possible: assignment.points_possible,
      lti_assignment_id: assignment.lti_context_id,
      lti_resource_link_id: assignment.lti_resource_link_id,
      lti_resource_link_id_duplicated_from: assignment.duplicate_of&.lti_resource_link_id,
      submission_types: assignment.submission_types
    }
    actl = assignment.assignment_configuration_tool_lookups.take
    domain = assignment.root_account&.domain(ApplicationController.test_cluster_name)
    event[:domain] = domain if domain
    if actl
      if (tool_proxy = Lti::ToolProxy.proxies_in_order_by_codes(
        context: assignment.course,
        vendor_code: actl.tool_vendor_code,
        product_code: actl.tool_product_code,
        resource_type_code: actl.tool_resource_type_code
      ).first)
        event[:associated_integration_id] = [actl.tool_vendor_code, actl.tool_product_code, tool_proxy.event_endpoint].join('_')
      end
    end
    event
  end

  def self.assignment_created(assignment)
    post_event_stringified('assignment_created', get_assignment_data(assignment))
  end

  def self.assignment_updated(assignment)
    post_event_stringified('assignment_updated', get_assignment_data(assignment))
  end

  def self.assignment_group_created(assignment_group)
    post_event_stringified('assignment_group_created', get_assignment_group_data(assignment_group))
  end

  def self.assignment_group_updated(assignment_group)
    post_event_stringified('assignment_group_updated', get_assignment_group_data(assignment_group))
  end

  def self.get_assignment_group_data(assignment_group)
    {
      assignment_group_id: assignment_group.id,
      context_id: assignment_group.context_id,
      context_type: assignment_group.context_type,
      name: assignment_group.name,
      position: assignment_group.position,
      group_weight: assignment_group.group_weight,
      sis_source_id: assignment_group.sis_source_id,
      integration_data: assignment_group.integration_data,
      rules: assignment_group.rules,
      workflow_state: assignment_group.workflow_state
    }
  end

  def self.assignments_bulk_updated(assignment_ids)
    Assignment.where(:id => assignment_ids).each{|a| assignment_updated(a)}
  end

  def self.submissions_bulk_updated(submissions)
    Submission.where(id: submissions).preload(:assignment).find_each { |submission| submission_updated(submission) }
  end

  def self.get_assignment_override_data(override)
    data_hash = {
      assignment_override_id: override.id,
      assignment_id: override.assignment_id,
      due_at: override.due_at,
      all_day: override.all_day,
      all_day_date: override.all_day_date,
      unlock_at: override.unlock_at,
      lock_at: override.lock_at,
      type: override.set_type,
      workflow_state: override.workflow_state,
    }

    case override.set_type
    when 'CourseSection'
      data_hash[:course_section_id] = override.set_id
    when 'Group'
      data_hash[:group_id] = override.set_id
    end

    data_hash
  end

  def self.assignment_override_created(override)
    post_event_stringified('assignment_override_created', get_assignment_override_data(override))
  end

  def self.assignment_override_updated(override)
    post_event_stringified('assignment_override_updated', get_assignment_override_data(override))
  end

  def self.get_submission_data(submission)
    event = {
      submission_id: submission.global_id,
      assignment_id: submission.global_assignment_id,
      user_id: submission.global_user_id,
      submitted_at: submission.submitted_at,
      lti_user_id: submission.lti_user_id,
      graded_at: submission.graded_at,
      updated_at: submission.updated_at,
      score: submission.score,
      grade: submission.grade,
      submission_type: submission.submission_type,
      body: LiveEvents.truncate(submission.body),
      url: submission.url,
      attempt: submission.attempt,
      late: submission.late?,
      missing: submission.missing?,
      lti_assignment_id: submission.assignment.lti_context_id,
      group_id: submission.group_id,
      posted_at: submission.posted_at,
      workflow_state: submission.workflow_state,
    }
    actl = submission.assignment.assignment_configuration_tool_lookups.take
    if actl
      if (tool_proxy = Lti::ToolProxy.proxies_in_order_by_codes(
        context: submission.course,
        vendor_code: actl.tool_vendor_code,
        product_code: actl.tool_product_code,
        resource_type_code: actl.tool_resource_type_code
      ).first)
        event[:associated_integration_id] = [actl.tool_vendor_code, actl.tool_product_code, tool_proxy.event_endpoint].join('_')
      end
    end
    event
  end

  def self.submission_event(event_type, submission)
    post_event_stringified(event_type, get_submission_data(submission), amended_context(submission.context))
  end

  def self.get_attachment_data(attachment)
    {
      attachment_id: attachment.global_id,
      user_id: attachment.global_user_id,
      display_name: LiveEvents.truncate(attachment.display_name),
      filename: LiveEvents.truncate(attachment.filename),
      context_type: attachment.context_type,
      context_id: attachment.global_context_id,
      content_type: attachment.content_type,
      folder_id: attachment.global_folder_id,
      unlock_at: attachment.unlock_at,
      lock_at: attachment.lock_at,
      updated_at: attachment.updated_at
    }
  end

  def self.submission_created(submission)
    submission_event('submission_created', submission)
  end

  def self.submission_updated(submission)
    submission_event('submission_updated', submission)
  end

  def self.submission_comment_created(comment)
    payload = {
      submission_comment_id: comment.id,
      submission_id: comment.submission_id,
      user_id: comment.author_id,
      created_at: comment.created_at,
      attachment_ids: comment.attachment_ids.blank? ? [] : comment.attachment_ids.split(','),
      body: LiveEvents.truncate(comment.comment)
    }
    post_event_stringified('submission_comment_created', payload)
  end

  def self.plagiarism_resubmit(submission)
    submission_event('plagiarism_resubmit', submission)
  end

  def self.get_user_data(user)
    {
      user_id: user.global_id,
      uuid: user.uuid,
      name: user.name,
      short_name: user.short_name,
      workflow_state: user.workflow_state,
      created_at: user.created_at,
      updated_at: user.updated_at,
      user_login: user.primary_pseudonym&.unique_id,
      user_sis_id: user.primary_pseudonym&.sis_user_id
    }
  end

  def self.user_created(user)
    post_event_stringified('user_created', get_user_data(user))
  end

  def self.user_updated(user)
    post_event_stringified('user_updated', get_user_data(user))
  end

  def self.get_enrollment_data(enrollment)
    data = {
      enrollment_id: enrollment.global_id,
      course_id: enrollment.global_course_id,
      user_id: enrollment.global_user_id,
      user_name: enrollment.user_name,
      type: enrollment.type,
      created_at: enrollment.created_at,
      updated_at: enrollment.updated_at,
      limit_privileges_to_course_section: enrollment.limit_privileges_to_course_section,
      course_section_id: enrollment.global_course_section_id,
      workflow_state: enrollment.workflow_state
    }
    data[:associated_user_id] = enrollment.global_associated_user_id if enrollment.observer?
    data
  end

  def self.enrollment_created(enrollment)
    post_event_stringified('enrollment_created', get_enrollment_data(enrollment))
  end

  def self.enrollment_updated(enrollment)
    post_event_stringified('enrollment_updated', get_enrollment_data(enrollment))
  end

  def self.get_enrollment_state_data(enrollment_state)
    {

      enrollment_id: enrollment_state.global_enrollment_id,
      state: enrollment_state.state,
      state_started_at: enrollment_state.state_started_at,
      state_is_current: enrollment_state.state_is_current,
      state_valid_until: enrollment_state.state_valid_until,
      restricted_access: enrollment_state.restricted_access,
      access_is_current: enrollment_state.access_is_current
    }
  end

  def self.enrollment_state_created(enrollment_state)
    post_event_stringified('enrollment_state_created', get_enrollment_state_data(enrollment_state))
  end

  def self.enrollment_state_updated(enrollment_state)
    post_event_stringified('enrollment_state_updated', get_enrollment_state_data(enrollment_state))
  end

  def self.user_account_association_created(assoc)
    post_event_stringified('user_account_association_created', {
      user_id: assoc.global_user_id,
      account_id: assoc.global_account_id,
      account_uuid: assoc.account.uuid,
      created_at: assoc.created_at,
      updated_at: assoc.updated_at,
      is_admin: !(assoc.account.root_account.cached_all_account_users_for(assoc.user).empty?),
    })
  end

  def self.logged_in(session, user, pseudonym)
    ctx = LiveEvents.get_context || {}
    ctx[:user_id] = user.global_id
    ctx[:user_login] = pseudonym.unique_id
    ctx[:user_account_id] = pseudonym.account.global_id
    ctx[:user_sis_id] = pseudonym.sis_user_id
    ctx[:session_id] = session[:session_id] if session[:session_id]
    post_event_stringified('logged_in', {
      redirect_url: session[:return_to]
    }, ctx)
  end

  def self.logged_out
    post_event_stringified('logged_out', {})
  end

  def self.quiz_submitted(submission)
    # TODO: include score, for automatically graded portions?
    post_event_stringified('quiz_submitted', {
      submission_id: submission.global_id,
      quiz_id: submission.global_quiz_id
    })
  end

  def self.wiki_page_created(page)
    post_event_stringified('wiki_page_created', {
      wiki_page_id: page.global_id,
      title: LiveEvents.truncate(page.title),
      body: LiveEvents.truncate(page.body)
    })
  end

  def self.wiki_page_updated(page, old_title, old_body)
    payload = {
      wiki_page_id: page.global_id,
      title: LiveEvents.truncate(page.title),
      body: LiveEvents.truncate(page.body)
    }

    if old_title
      payload[:old_title] = LiveEvents.truncate(old_title)
    end

    if old_body
      payload[:old_body] = LiveEvents.truncate(old_body)
    end

    post_event_stringified('wiki_page_updated', payload)
  end

  def self.wiki_page_deleted(page)
    post_event_stringified('wiki_page_deleted', {
      wiki_page_id: page.global_id,
      title: LiveEvents.truncate(page.title)
    })
  end

  def self.attachment_created(attachment)
    post_event_stringified('attachment_created', get_attachment_data(attachment))
  end

  def self.attachment_updated(attachment, old_display_name)
    payload = get_attachment_data(attachment)
    if old_display_name
      payload[:old_display_name] = LiveEvents.truncate(old_display_name)
    end

    post_event_stringified('attachment_updated', payload)
  end

  def self.attachment_deleted(attachment)
    post_event_stringified('attachment_deleted', get_attachment_data(attachment))
  end

  def self.grade_changed(submission, old_submission=nil, old_assignment=submission.assignment)
    grader_id = nil
    if submission.grader_id && !submission.autograded?
      grader_id = submission.global_grader_id
    end

    sis_pseudonym = GuardRail.activate(:secondary) do
      SisPseudonym.for(submission.user, submission.assignment.context, type: :trusted, require_sis: false)
    end

    post_event_stringified('grade_change', {
      submission_id: submission.global_id,
      assignment_id: submission.global_assignment_id,
      assignment_name: submission.assignment.name,
      grade: submission.grade,
      old_grade: old_submission.try(:grade),
      score: submission.score,
      old_score: old_submission.try(:score),
      points_possible: submission.assignment.points_possible,
      old_points_possible: old_assignment.points_possible,
      grader_id: grader_id,
      student_id: submission.global_user_id,
      student_sis_id: sis_pseudonym&.sis_user_id,
      user_id: submission.global_user_id,
      grading_complete: submission.graded?,
      muted: !submission.posted?
    }, amended_context(submission.assignment.context))
  end

  def self.asset_access(asset, category, role, level, context: nil, context_membership: nil)
    asset_subtype = nil
    if asset.is_a?(Array)
      asset_subtype = asset[0]
      asset_obj = asset[1]
    else
      asset_obj = asset
    end

    enrollment_data = {}
    if context_membership&.is_a?(Enrollment)
      enrollment_data = {
        enrollment_id: context_membership.id,
        section_id: context_membership.course_section_id
      }
    end

    post_event_stringified(
      'asset_accessed',
      {
        asset_name: asset_obj.try(:name) || asset_obj.try(:title),
        asset_type: asset_obj.class.reflection_type_name,
        asset_id: asset_obj.global_id,
        asset_subtype: asset_subtype,
        category: category,
        role: role,
        level: level
      }.merge(LiveEvents::EventSerializerProvider.serialize(asset_obj)).merge(enrollment_data),
      amended_context(context)
    )
  end

  def self.quiz_export_complete(content_export)
    payload = content_export.settings[:quizzes2]
    post_event_stringified('quiz_export_complete', payload, amended_context(content_export.context))
  end

  def self.content_migration_completed(content_migration)
    post_event_stringified(
      'content_migration_completed',
      content_migration_data(content_migration),
      amended_context(content_migration.context)
    )
  end

  def self.content_migration_data(content_migration)
    context = content_migration.context
    import_quizzes_next =
      content_migration.migration_settings&.[](:import_quizzes_next) == true
    payload = {
      content_migration_id: content_migration.global_id,
      context_id: context.global_id,
      context_type: context.class.to_s,
      lti_context_id: context.lti_context_id,
      context_uuid: context.uuid,
      import_quizzes_next: import_quizzes_next
    }

    if context.respond_to?(:root_account)
      payload[:domain] = context.root_account&.domain(ApplicationController.test_cluster_name)
    end

    payload
  end

  def self.course_section_created(section)
    post_event_stringified('course_section_created', get_course_section_data(section))
  end

  def self.course_section_updated(section)
    post_event_stringified('course_section_updated', get_course_section_data(section))
  end

  def self.quizzes_next_quiz_duplicated(payload)
    post_event_stringified('quizzes_next_quiz_duplicated', payload)
  end

  def self.get_course_section_data(section)
    {
      course_section_id: section.id,
      sis_source_id: section.sis_source_id,
      sis_batch_id: section.sis_batch_id,
      course_id: section.course_id,
      root_account_id: section.root_account_id,
      enrollment_term_id: section.enrollment_term_id,
      name: section.name,
      default_section: section.default_section,
      accepting_enrollments: section.accepting_enrollments,
      can_manually_enroll: section.can_manually_enroll,
      start_at: section.start_at,
      end_at: section.end_at,
      workflow_state: section.workflow_state,
      restrict_enrollments_to_section_dates: section.restrict_enrollments_to_section_dates,
      nonxlist_course_id: section.nonxlist_course_id,
      stuck_sis_fields: section.stuck_sis_fields,
      integration_id: section.integration_id
    }
  end

  def self.module_created(context_module)
    post_event_stringified('module_created', get_context_module_data(context_module))
  end

  def self.module_updated(context_module)
    post_event_stringified('module_updated', get_context_module_data(context_module))
  end

  def self.get_context_module_data(context_module)
    {
      module_id: context_module.id,
      context_id: context_module.context_id,
      context_type: context_module.context_type,
      name: context_module.name,
      position: context_module.position,
      workflow_state: context_module.workflow_state
    }
  end

  def self.module_item_created(context_module_item)
    post_event_stringified('module_item_created', get_context_module_item_data(context_module_item))
  end

  def self.module_item_updated(context_module_item)
    post_event_stringified('module_item_updated', get_context_module_item_data(context_module_item))
  end

  def self.get_context_module_item_data(context_module_item)
    {
      module_item_id: context_module_item.id,
      module_id: context_module_item.context_module_id,
      context_id: context_module_item.context_id,
      context_type: context_module_item.context_type,
      position: context_module_item.position,
      workflow_state: context_module_item.workflow_state
    }
  end

  def self.course_completed(context_module_progression, overridden_requirements_met: nil)
    post_event_stringified('course_completed',
      get_course_completed_data(
        context_module_progression.context_module.course,
        context_module_progression.user,
        overridden_requirements_met: overridden_requirements_met
      ))
  end

  def self.course_progress(context_module_progression)
    post_event_stringified('course_progress', get_course_completed_data(context_module_progression.context_module.course, context_module_progression.user))
  end

  def self.get_course_completed_data(course, user, overridden_requirements_met: nil)
    {
      progress: CourseProgress.new(course, user, read_only: true, overridden_requirements_met: overridden_requirements_met).to_json,
      user: user.slice(%i[id name email]),
      course: course.slice(%i[id name account_id sis_source_id])
    }
  end

  def self.get_learning_outcome_result_data(result)
    {
      learning_outcome_id: result.learning_outcome_id,
      mastery: result.mastery,
      score: result.score,
      created_at: result.created_at,
      attempt: result.attempt,
      possible: result.possible,
      original_score: result.original_score,
      original_possible: result.original_possible,
      original_mastery: result.original_mastery,
      assessed_at: result.assessed_at,
      title: result.title,
      percent: result.percent
    }
  end

  def self.learning_outcome_result_updated(result)
    post_event_stringified('learning_outcome_result_updated', get_learning_outcome_result_data(result).merge(updated_at: result.updated_at))
  end

  def self.learning_outcome_result_created(result)
    post_event_stringified('learning_outcome_result_created', get_learning_outcome_result_data(result))
  end

  def self.get_learning_outcome_data(outcome)
    {
      learning_outcome_id: outcome.id,
      context_type: outcome.context_type,
      context_id: outcome.context_id,
      display_name: outcome.display_name,
      short_description: outcome.short_description,
      description: outcome.description,
      vendor_guid: outcome.vendor_guid,
      calculation_method: outcome.calculation_method,
      calculation_int: outcome.calculation_int,
      rubric_criterion: outcome.rubric_criterion,
      title: outcome.title,
      workflow_state: outcome.workflow_state
    }
  end

  def self.learning_outcome_updated(outcome)
    post_event_stringified('learning_outcome_updated', get_learning_outcome_data(outcome).merge(updated_at: outcome.updated_at))
  end

  def self.learning_outcome_created(outcome)
    post_event_stringified('learning_outcome_created', get_learning_outcome_data(outcome))
  end

  def self.get_learning_outcome_group_data(group)
    {
      learning_outcome_group_id: group.id,
      context_id: group.context_id,
      context_type: group.context_type,
      title: group.title,
      description: group.description,
      vendor_guid: group.vendor_guid,
      parent_outcome_group_id: group.learning_outcome_group_id,
      workflow_state: group.workflow_state
    }
  end

  def self.learning_outcome_group_updated(group)
    post_event_stringified('learning_outcome_group_updated', get_learning_outcome_group_data(group).merge(updated_at: group.updated_at))
  end

  def self.learning_outcome_group_created(group)
    post_event_stringified('learning_outcome_group_created', get_learning_outcome_group_data(group))
  end

  def self.get_learning_outcome_link_data(link)
    {
      learning_outcome_link_id: link.id,
      learning_outcome_id: link.content_id,
      learning_outcome_group_id: link.associated_asset_id,
      context_id: link.context_id,
      context_type: link.context_type,
      workflow_state: link.workflow_state
    }
  end

  def self.learning_outcome_link_created(link)
    post_event_stringified('learning_outcome_link_created', get_learning_outcome_link_data(link))
  end

  def self.learning_outcome_link_updated(link)
    post_event_stringified('learning_outcome_link_updated', get_learning_outcome_link_data(link).merge(updated_at: link.updated_at))
  end

  def self.grade_override(score, old_score, enrollment, course)
    return unless score.course_score && score.override_score != old_score
    data = {
      score_id: score.id,
      enrollment_id: score.enrollment_id,
      user_id: enrollment.user_id,
      course_id: enrollment.course_id,
      grading_period_id: score.grading_period_id,
      override_score: score.override_score,
      old_override_score: old_score,
      updated_at: score.updated_at,
    }
    post_event_stringified('grade_override', data, amended_context(course))
  end

  def self.course_grade_change(score, old_score_values, enrollment)
    data = {
      user_id: enrollment.user_id,
      course_id: enrollment.course_id,
      workflow_state: score.workflow_state,
      created_at: score.created_at,
      updated_at: score.updated_at,
      current_score: score.current_score,
      old_current_score: old_score_values[:current_score],
      final_score: score.final_score,
      old_final_score: old_score_values[:final_score],
      unposted_current_score: score.unposted_current_score,
      old_unposted_current_score: old_score_values[:unposted_current_score],
      unposted_final_score: score.unposted_final_score,
      old_unposted_final_score: old_score_values[:unposted_final_score]
    }
    post_event_stringified('course_grade_change', data, amended_context(score.course))
  end

  def self.sis_batch_payload(batch)
    {
      sis_batch_id: batch.id,
      account_id: batch.account_id,
      workflow_state: batch.workflow_state
    }
  end

  def self.sis_batch_created(batch)
    post_event_stringified('sis_batch_created', sis_batch_payload(batch))
  end

  def self.sis_batch_updated(batch)
    post_event_stringified('sis_batch_updated', sis_batch_payload(batch))
  end

  def self.outcome_proficiency_created(proficiency)
    post_event_stringified('outcome_proficiency_created', get_outcome_proficiency_data(proficiency))
  end

  def self.outcome_proficiency_updated(proficiency)
    post_event_stringified('outcome_proficiency_updated', get_outcome_proficiency_data(proficiency).merge(updated_at: proficiency.updated_at))
  end

  def self.get_outcome_proficiency_data(proficiency)
    ratings = proficiency.outcome_proficiency_ratings.map do |rating|
      get_outcome_proficiency_rating_data(rating)
    end
    {
      outcome_proficiency_id: proficiency.id,
      context_type: proficiency.context_type,
      context_id: proficiency.context_id,
      workflow_state: proficiency.workflow_state,
      outcome_proficiency_ratings: ratings
    }
  end

  def self.get_outcome_proficiency_rating_data(rating)
    {
      outcome_proficiency_rating_id: rating.id,
      description: rating.description,
      points: rating.points,
      mastery: rating.mastery,
      color: rating.color,
      workflow_state: rating.workflow_state
    }
  end

  def self.outcome_calculation_method_created(method)
    post_event_stringified('outcome_calculation_method_created', get_outcome_calculation_method_data(method))
  end

  def self.outcome_calculation_method_updated(method)
    post_event_stringified('outcome_calculation_method_updated', get_outcome_calculation_method_data(method).merge(updated_at: method.updated_at))
  end

  def self.get_outcome_calculation_method_data(method)
    {
      outcome_calculation_method_id: method.id,
      context_type: method.context_type,
      context_id: method.context_id,
      workflow_state: method.workflow_state,
      calculation_method: method.calculation_method,
      calculation_int: method.calculation_int
    }
  end
end
