# frozen_string_literal: true
# Represents a category of assessments. This is typically 'Mission' and 'Training'.
class Course::Assessment::Category < ApplicationRecord
  include Course::ModelComponentHost::Component
  has_one_folder

  validates :title, length: { maximum: 255 }, presence: true
  validates :weight, numericality: { only_integer: true }, presence: true
  validates :creator, presence: true
  validates :updater, presence: true
  validates :course, presence: true

  belongs_to :course, inverse_of: :assessment_categories
  has_many :tabs, class_name: 'Course::Assessment::Tab',
                  inverse_of: :category,
                  dependent: :destroy
  has_many :assessments, through: :tabs
  has_many :setting_emails, class_name: 'Course::Settings::Email',
                            foreign_key: :course_assessment_category_id,
                            inverse_of: :assessment_category,
                            dependent: :destroy

  accepts_nested_attributes_for :tabs

  after_initialize :build_initial_tab, if: :new_record?
  after_initialize :set_folder_start_at, if: :new_record?
  before_validation :assign_folder_attributes
  before_destroy :validate_before_destroy

  default_scope { order(:weight) }

  def self.after_course_initialize(course)
    return if course.persisted? || !course.assessment_categories.empty?

    course.assessment_categories.
      build(title: human_attribute_name('title.default'), weight: 0)
  end

  # Returns a boolean value indicating if there are other categories
  # besides this one remaining in its course.
  #
  # @return [Boolean]
  def other_categories_remaining?
    course.assessment_categories.count > 1
  end

  def initialize_duplicate(duplicator, other)
    self.folder = duplicator.duplicate(other.folder)
    self.course = duplicator.options[:destination_course]
    tabs << other.tabs.select { |tab| duplicator.duplicated?(tab) }.map do |tab|
      duplicator.duplicate(tab).tap do |duplicate_tab|
        duplicate_tab.assessments.each { |assessment| assessment.folder.parent = folder }
      end
    end
    setting_emails << other.setting_emails.
                      select { |setting_email| duplicator.duplicated?(setting_email) }.
                      map { |setting_email| duplicator.duplicate(setting_email) }
  end

  # @return [Boolean] true if post-duplication processing is successful.
  def after_duplicate_save(duplicator)
    User.with_stamper(duplicator.options[:current_user]) do
      Course::Settings::Email.build_assessment_email_settings(self)
      save
      build_initial_tab ? save : true
    end
  end

  private

  def build_initial_tab
    return unless tabs.empty?

    tabs.build(title: Course::Assessment::Tab.human_attribute_name('title.default'),
               weight: 0, category: self)
  end

  def set_folder_start_at
    folder.start_at = Time.zone.now
  end

  def assign_folder_attributes
    folder.assign_attributes(name: title, course: course, parent: course.root_folder)
  end

  def validate_before_destroy
    return true if course.destroying? || other_categories_remaining?

    errors.add(:base, :deletion)
    throw(:abort)
  end
end
