class Ecs::CalculateCourseEvaluationService < ApplicationService
  attr_reader :ec_course

  def initialize(ec_course)
    @ec_course = ec_course
  end

  def call
    ActiveRecord::Base.transaction do
      clear_student_score!

      calculate_student_score_target!

      calculate_graduation_requirement!
    end
  end

  private

  def clear_student_score!
    ec_course.ec_course_student_scores.destroy_all
  end

  def requirement_passed?(standard_value, real_value)
    standard_value && real_value && real_value >= standard_value ? 1 : 0
  end

  def calculate_student_score_target!
    complete_target_count = 0
    course_targets = ec_course.ec_course_targets.includes(ec_achievement_evaluation_relates: :ec_course_achievement_method)
    course_targets.find_each do |target|
      target.ec_achievement_evaluation_relates.each do |relate|
        achievement_method = relate.ec_course_achievement_method

        total = achievement_method.ec_achievement_evaluation_relates.count
        percentage = total.zero? ? 0 : achievement_method.percentage.fdiv(total)

        achievements = EcStudentAchievement.where(ec_course_evaluation_id: achievement_method.ec_course_evaluation_id)

        achievements =
          if relate.ec_course_evaluation_subitem_id.blank? || relate.ec_course_evaluation_subitem_id == -1
            achievements.where(position: relate.position)
          else
            achievements.where(ec_course_evaluation_subitem_id: relate.ec_course_evaluation_subitem_id)
          end

        # 遍历学生成绩统计数据
        achievements.find_each do |achievement|
          student_score = EcCourseStudentScore.find_or_initialize_by(
            ec_course_id: ec_course.id,
            ec_year_student_id: achievement.ec_year_student_id
          )

          score = achievement_method.score.zero? || achievement.score.nil? ? 0 : (achievement.fdiv(achievement_method.score) * percentage).round(3)

          if student_score.new_record?
            student_score.student_name = achievement.student_name
            student_score.student_number = achievement.student_number
            student_score.save!

            create_params = {
              ec_course_id: ec_course.id, ec_year_student_id: achievement.ec_year_student_id,
              ec_course_target_id: target.id, eaer_id: relate.id,
              ec_target_position: target.position, score: score
            }
            student_score.ec_student_score_targets.create!(create_params)
          else
            score_target = EcStudentScoreTarget.find_or_initialize_by(
              ec_course_id: ec_course.id,
              ec_year_student_id: achievement.ec_year_student_id,
              ec_course_student_score_id: student_score.id,
              ec_course_target_id: target.id,
              ec_target_position: target.position,
              eaer_id: relate.id
            )

            score_target.score = score_target.score.to_f + score
            score_target.save!
          end
        end
      end

      # 计算该课程目标是否完成
      count = target.ec_student_score_targets.count
      score = target.ec_student_score_targets.sum(:score)
      average = count.zero? ? 0 : score.fdiv(count)
      complete_target_count += 1 if target.standard_grade && target.standard_grade <= average
    end

    ec_course.update!(complete_target_count: complete_target_count)
  end

  def calculate_graduation_requirement!
    student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id)
    student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id')
    student_score_map = student_scores.group_by { |item| item.ec_course_target_id }

    subitem_targets = ec_course.ec_graduation_subitem_course_targets.includes(:ec_graduation_subitem, :ec_course_target)
    subitem_targets.group_by { |subitem_target| subitem_target.ec_graduation_subitem }.each do |subitem, subitem_target_arr|
      support = subitem.ec_course_supports.find_by(ec_course_id: ec_course.id)
      next if support.blank?

      total_weight = 0.0
      total_score = 0.0
      subitem_target_arr.each do |subitem_target|
        target = subitem_target.ec_course_target
        student_score = student_score_map[target.id].first

        total_weight += target.weigths.to_f
        total_score += student_score.average_score.round(2) * target.weigths.to_f
      end

      target_value = support.weights.to_f * ec_course.ec_year.calculation_value.to_f
      real_value = total_weight.zero? ? 0 : (total_score * support.weights.to_f) / (total_weight * 100)

      cal = support.ec_graduation_requirement_calculation || support.build_ec_graduation_requirement_calculation

      cal.target_value = target_value.round(3)
      cal.real_value   = real_value.round(3)
      cal.status       = requirement_passed?(target_value, real_value)
      cal.save!
    end
  end
end