# Takes a dirtied LibraryEntry and generates a list of LibraryEvents for the changes
class LibraryEventService
  # The change values to store in the event
  CHANGES_FOR_EVENT = {
    rated: %w[rating],
    progressed: %w[progress reconsume_count volumes_owned time_spent],
    updated: %w[status reconsume_count],
    reacted: %w[media_reaction_id],
    annotated: %w[notes]
  }.freeze

  # @param library_entry [LibraryEntry] the dirty LibraryEntry to figure out events for
  def initialize(entry)
    @entry = entry
  end

  # @return [Array<LibraryEvent>] a list of (unsaved) LibraryEvents generated by this changeset
  def events
    return [] if @entry.imported
    [rated_event, progressed_event, updated_event, reacted_event, annotated_event].compact!
  end

  def create_events!
    LibraryEvent.transaction { events.map(&:save!) }
  end

  private

  def rated_event
    event_for(:rated) if @entry.saved_change_to_rating?
  end

  def progressed_event
    if @entry.saved_change_to_progress? || @entry.saved_change_to_reconsume_count? ||
       @entry.saved_change_to_volumes_owned?
      event_for(:progressed)
    end
  end

  def updated_event
    event_for(:updated) if @entry.saved_change_to_status?
  end

  def reacted_event
    event_for(:reacted) if @entry.saved_change_to_media_reaction_id?
  end

  def annotated_event
    event_for(:annotated) if @entry.saved_change_to_notes?
  end

  def event_for(kind)
    LibraryEvent.new(
      kind: kind,
      changed_data: @entry.saved_changes.slice(*CHANGES_FOR_EVENT[kind]),
      library_entry_id: @entry.id,
      anime_id: @entry.anime_id,
      manga_id: @entry.manga_id,
      drama_id: @entry.drama_id,
      user_id: @entry.user_id
    )
  end
end
