class CopyEcYearService < ApplicationService
  attr_reader :major_school, :to_year

  def initialize(major_school, year)
    @major_school = major_school
    @to_year      = major_school.ec_years.new(year: year)
  end

  def call
    if from_year.blank?
      to_year.save!
      return to_year
    end

    # 专业第一次创建届别时，复制示例专业2017届
    ActiveRecord::Base.transaction do
      copy_ec_year!

      copy_graduation_requirement!

      copy_training_objective!

      new_major_school? ? copy_template_ec_course! : copy_ec_courses!
    end

    to_year
  end

  private

  def new_major_school?
    @_new_major ||= major_school.ec_years.count.zero?
  end

  def from_year
    @_from_year ||= new_major_school? ? template_major_year : to_year.prev_year
  end

  def template_major_year
    EcYear.joins(:ec_major_school).where(ec_major_schools: { template_major: true }).find_by_year('2017')
  end

  def copy_ec_year!
    to_year.calculation_value = from_year.calculation_value
    to_year.save!
  end

  def copy_graduation_requirement!
    requirements = from_year.ec_graduation_requirements.includes(ec_graduation_subitems: :ec_require_sub_vs_standards)

    requirements.each do |requirement|
      to_requirement = to_year.ec_graduation_requirements.new
      to_requirement.attributes = requirement.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at')
      to_requirement.save!

      # 记录对应关系，创建支撑时使用
      graduation_requirement_map[requirement.id] = to_requirement.id

      copy_graduation_subitems(requirement, to_requirement)
    end
  end

  def copy_graduation_subitems(requirement, to_requirement)
    requirement.ec_graduation_subitems.each do |item|
      to_item = to_requirement.ec_graduation_subitems.new
      to_item.attributes = item.attributes.except('id', 'ec_graduation_requirement_id', 'created_at', 'updated_at')
      to_item.save!

      # 记录对应关系，创建支撑时使用
      graduation_subitem_map[item.id] = to_item.id

      copy_requirement_standard_supports!(item, to_item)
    end
  end

  def copy_requirement_standard_supports!(graduation_subitem, to_graduation_subitem)
    graduation_subitem.ec_require_sub_vs_standards.each do |support|
      to_support = to_graduation_subitem.ec_require_sub_vs_standards.new
      to_support.attributes = support.attributes.except('id', 'ec_graduation_subitem_id', 'created_at', 'updated_at')
      to_support.save!
    end
  end

  def copy_training_objective!
    training_objective = from_year.ec_training_objective
    return if training_objective.blank?

    attributes = training_objective.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at')
    to_training_objective = to_year.create_ec_training_objective!(attributes)

    copy_training_subitems!(training_objective, to_training_objective)
  end

  def copy_training_subitems!(training_objective, to_training_objective)
    training_subitems = training_objective.ec_training_subitems.includes(:ec_requirement_vs_objectives)

    training_subitems.each do |item|
      to_item = to_training_objective.ec_training_subitems.new
      to_item.attributes = item.attributes.except('id', 'ec_training_objective_id', 'created_at', 'updated_at')
      to_item.save!

      copy_requirement_vs_objectives!(item, to_item)
    end
  end

  def copy_requirement_vs_objectives!(training_item, to_training_item)
    training_item.ec_requirement_vs_objectives.each do |support|
      to_support = to_training_item.ec_requirement_vs_objectives.new(status: support.status)
      to_support.ec_graduation_requirement_id = graduation_requirement_map[support.ec_graduation_requirement_id]
      to_support.save!
    end
  end

  def copy_template_ec_course!
    course = from_year.ec_courses.includes(
      :ec_score_levels,
      ec_course_evaluations: :ec_course_evaluation_subitems,
      ec_course_targets: :ec_graduation_subitem_course_targets,
      ec_course_achievement_methods: :ec_achievement_evaluation_relates,
      ec_course_supports: :ec_graduation_subitem_courses
    ).find_by_name('数据库原理')

    to_course = to_year.ec_courses.new
    to_course.attributes = course.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at')
    to_course.save!

    course_map[course.id] = to_course.id

    copy_course_evaluations!(course, to_course)
    copy_course_targets!(course, to_course)
    copy_course_achievement_methods!(course, to_course)
    copy_ec_course_supports!(course, to_course)
    copy_score_levels!(course, to_course)

    # 复制示例时需要复制学生和成绩数据
    copy_year_students!
  end

  def copy_ec_courses!
    courses = from_year.ec_courses.includes(
      :ec_score_levels,
      ec_course_evaluations: :ec_course_evaluation_subitems,
      ec_course_targets: :ec_graduation_subitem_course_targets,
      ec_course_achievement_methods: :ec_achievement_evaluation_relates,
      ec_course_supports: :ec_graduation_subitem_courses
    )

    courses.each do |course|
      to_course = to_year.ec_courses.new
      to_course.attributes = course.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at')
      to_course.save!

      course_map[course.id] = to_course.id

      copy_course_evaluations!(course, to_course)
      copy_course_targets!(course, to_course)
      copy_course_achievement_methods!(course, to_course)
      copy_ec_course_supports!(course, to_course)
      copy_score_levels!(course, to_course)
    end
  end

  def copy_course_evaluations!(course, to_course)
    course.ec_course_evaluations.each do |evaluation|
      to_evaluation = to_course.ec_course_evaluations.new
      to_evaluation.attributes = evaluation.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at')
      to_evaluation.save!

      course_evaluation_map[evaluation.id] = to_evaluation.id

      copy_course_evaluation_subitems!(evaluation, to_evaluation)
    end
  end

  def copy_course_evaluation_subitems!(evaluation, to_evaluation)
    evaluation.ec_course_evaluation_subitems.each do |item|
      to_item = to_evaluation.ec_course_evaluation_subitems.new
      to_item.attributes = item.attributes.except('id', 'ec_course_evaluation_id', 'created_at', 'updated_at')
      to_item.save!

      course_evaluation_subitem_map[item.id] = to_item.id
    end
  end

  def copy_course_targets!(course, to_course)
    course.ec_course_targets.each do |target|
      to_target = to_course.ec_course_targets.new
      to_target.attributes = target.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at')
      to_target.save!

      course_target_map[target.id] = to_target.id

      copy_graduation_subitem_course_targets!(target, to_target)
    end
  end

  def copy_graduation_subitem_course_targets!(target, to_target)
    target.ec_graduation_subitem_course_targets.each do |support|
      to_support = to_target.ec_graduation_subitem_course_targets.new
      to_support.attributes = support.attributes.except('id', 'ec_course_target_id', 'ec_graduation_subitem_id', 'created_at', 'updated_at')
      to_support.ec_graduation_subitem_id = graduation_subitem_map[support.ec_graduation_subitem_id]
      to_support.save!
    end
  end

  def copy_course_achievement_methods!(course, to_course)
    course.ec_course_achievement_methods.each do |from|
      to            = to_course.ec_course_achievement_methods.new
      to.attributes = from.attributes.except('id', 'ec_course_id', 'ec_course_target_id', 'ec_course_evaluation_id',
                                             'ec_course_evaluation_subitem_id', 'created_at', 'updated_at')

      to.ec_course_target_id             = course_target_map[from.ec_course_target_id]
      to.ec_course_evaluation_id         = course_evaluation_map[from.ec_course_evaluation_id]
      to.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[from.ec_course_evaluation_subitem_id]
      to.save!

      copy_achievement_evaluation_relates!(from, to)
    end
  end

  def copy_achievement_evaluation_relates!(method, to_method)
    method.ec_achievement_evaluation_relates.each do |relate|
      to_relate = to_method.ec_achievement_evaluation_relates.new
      to_relate.attributes = relate.attributes.except('id', 'ec_course_achievement_method_id', 'ec_course_target_id',
                                                      'ec_course_evaluation_subitem_id', 'created_at', 'updated_at')
      to_relate.ec_course_target_id             = course_target_map[relate.ec_course_target_id]
      # 可能不存在，所以为 -1
      to_relate.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[relate.ec_course_evaluation_subitem_id] || -1
      to_relate.save!

      achievement_evaluation_relates_map[relate.id] = to_relate.id
    end
  end

  def copy_ec_course_supports!(course, to_course)
    course.ec_course_supports.each do |support|
      to_support = to_course.ec_course_supports.new
      to_support.attributes = support.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at')
      to_support.save!

      copy_graduation_subitem_courses!(support, to_support)
    end
  end

  def copy_graduation_subitem_courses!(course_support, to_course_support)
    course_support.ec_graduation_subitem_courses.each do |item|
      to_item = to_course_support.ec_graduation_subitem_courses.new
      to_item.attributes = item.attributes.except('id', 'ec_course_support_id', 'ec_graduation_subitem_id',
                                                  'created_at', 'updated_at')
      to_item.ec_graduation_subitem_id = graduation_subitem_map[item.ec_graduation_subitem_id]
      to_item.save!
    end
  end

  def copy_score_levels!(course, to_course)
    course.ec_score_levels.each do |level|
      to_level = to_course.ec_score_levels.new
      to_level.attributes = level.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at')
      to_level.save!
    end
  end

  def copy_year_students!
    students = from_year.ec_year_students.includes(:ec_student_achievements, :ec_course_student_scores, :ec_student_score_targets)

    students.each do |student|
      to_student = to_year.ec_year_students.new
      to_student.attributes = student.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at')
      to_student.save!

      copy_student_achievements!(student, to_student)
      copy_course_student_scores!(student, to_student)
      copy_student_score_targets!(student, to_student)
    end
  end

  def copy_student_achievements!(student, to_student)
    student.ec_student_achievements.each do |achievement|
      to_achievement = to_student.ec_student_achievements.new
      to_achievement.attributes = achievement.attributes.except('id', 'ec_year_student_id', 'ec_course_evaluation_id',
                                                                'ec_course_evaluation_subitem_id', 'created_at', 'updated_at')
      to_achievement.ec_course_evaluation_id = course_evaluation_map[achievement.ec_course_evaluation_id]
      to_achievement.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[achievement.ec_course_evaluation_subitem_id]
      to_achievement.save!
    end
  end

  def copy_course_student_scores!(student, to_student)
    student.ec_course_student_scores.each do |score|
      to_score = to_student.ec_course_student_scores.new
      to_score.attributes = score.attributes.except('id', 'ec_year_student_id', 'ec_course_id', 'created_at', 'updated_at')
      to_score.ec_course_id = course_map[score.ec_course_id]
      to_score.save!

      course_student_score_map[score.id] = to_score.id
    end
  end

  def copy_student_score_targets!(student, to_student)
    student.ec_student_score_targets.each do |target|
      to_target = to_student.ec_student_score_targets.new
      to_target.attributes = target.attributes.except('id', 'ec_course_id', 'ec_course_student_score_id',
                                                      'ec_course_target_id', 'ec_year_student_id', 'eaer_id',
                                                      'created_at', 'updated_at')
      to_target.ec_course_id               = course_map[target.ec_course_id]
      to_target.ec_course_student_score_id = course_student_score_map[target.ec_course_student_score_id]
      to_target.ec_course_target_id        = course_target_map[target.ec_course_target_id]
      to_target.eaer_id                    = achievement_evaluation_relates_map[target.eaer_id]
      to_target.save!
    end
  end

  def graduation_requirement_map
    @_graduation_requirement_map ||= {}
  end

  def graduation_subitem_map
    @_graduation_subitem_map ||= {}
  end

  def course_map
    @_course_map ||= {}
  end

  def course_evaluation_map
    @_course_evaluation_map ||= {}
  end

  def course_evaluation_subitem_map
    @_course_evaluation_subitem_map ||= {}
  end

  def achievement_evaluation_relates_map
    @_achievement_evaluation_relates_map ||= {}
  end

  def course_target_map
    @_course_target_map ||= {}
  end

  def course_student_score_map
    @_course_student_score_map ||= {}
  end
end