class HomeworksService

  # 创建实训作业
  def create_homework shixun, course, category, current_user
    ActiveRecord::Base.transaction do
      homework = HomeworkCommon.new(name: shixun.name, description: shixun.description, homework_type: 4,
                                    user_id: current_user.id, course_id: course.id,
                                    course_second_category_id: category.try(:id).to_i)

      homework_detail_manual = HomeworkDetailManual.new
      homework.homework_detail_manual = homework_detail_manual

      if homework.save!
        homework_detail_manual.save! if homework_detail_manual
        HomeworkCommonsShixun.create!(homework_common_id: homework.id, shixun_id: shixun.id)
        HomeworksService.new.create_shixun_homework_cha_setting(homework, shixun)
        HomeworksService.new.create_works_list(homework, course)
      end
      homework
    end
  end

  #更新实训作业的状态
  def update_shixun_work_status homework
    shixun = homework.shixuns.first
    student_works = homework.student_works.unfinished
    homework_challenge_settings = homework.homework_challenge_settings
    challeng_ids = homework_challenge_settings.map(&:challenge_id)
    # 取已发布的作品
    if homework.unified_setting
      student_works = student_works
    else
      setting = homework.homework_group_settings.group_published
      if setting.blank?
        student_works = student_works.none
      else
        users = homework.course.course_members.course_find_by_ids("course_group_id",setting.map(&:course_group_id))
        student_works = student_works.homework_by_user(users.map(&:user_id))
      end
    end
    # 已发布作品且状态为未提交的作品 如果有开启过实训则更新状态
    myshixuns = Myshixun.where(:shixun_id => shixun.id, :user_id => student_works.map(&:user_id))
    myshixuns.each do |myshixun|
      work = student_works.homework_by_user(myshixun.user_id).first
      setting_time = homework.homework_group_setting myshixun.user_id
      games = myshixun.games.where(:challenge_id => challeng_ids)
      myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil
      compelete_status = 0
      if myshixun_endtime.present? && myshixun_endtime < setting_time.end_time
        if myshixun_endtime < setting_time.publish_time
          compelete_status = 2
        else
          compelete_status = 1
        end
      end
      if setting_time.end_time > Time.now
        work.update_attributes(:work_status => 1, :late_penalty => 0, :commit_time => myshixun.updated_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id, :compelete_status => compelete_status)
      else
        work.update_attributes(:work_status => ((myshixun.is_complete? && (myshixun.done_time < setting_time.end_time)) ? 1 : 2), :late_penalty => (myshixun.is_complete? && (myshixun.done_time < setting_time.end_time) ? 0 : homework.late_penalty), :commit_time => myshixun.updated_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id, :compelete_status => compelete_status)
      end
      set_shixun_final_score work
    end
    # 更新所有学生的效率分
    HomeworksService.new.update_student_eff_score HomeworkCommon.where(:id => homework.id).first
  end

  # 实训作业的评分
  def set_shixun_final_score student_work
    homework = student_work.homework_common
    answer_open_evaluation = homework.homework_detail_manual.answer_open_evaluation
    myshixun = student_work.myshixun
    if student_work.work_status != 0 && myshixun.present?
      final_score = 0
      compelete = true
      max_endtime = ""
      user_total_score = 0
      pass_consume_time = 0
      homework.homework_challenge_settings.each do |setting|
        game = myshixun.games.find_by(challenge_id: setting.challenge_id, status: 2)
        unless game.nil?
          pass_consume_time += (game.cost_time / 60.0).to_f
          user_total_score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i
          adjust_score = student_work.challenge_work_scores.where(challenge_id: setting.challenge_id).last
          final_score += adjust_score.present? ? adjust_score.score : (answer_open_evaluation ? setting.score : (game.final_score > 0 ? game.real_score(setting.score) : 0))
          max_endtime = max_endtime == "" ? game.end_time : (game.end_time > max_endtime ? game.end_time : max_endtime)
        else
          compelete = false
        end
      end

      if compelete && max_endtime != ""
        homework = student_work.homework_common
        setting_time = homework.homework_group_setting student_work.user_id
        if setting_time.publish_time.present? && setting_time.end_time.present?
          if max_endtime < setting_time.publish_time
            student_work.compelete_status = 2
          else
            if max_endtime < setting_time.end_time || (homework.allow_late && (homework.course.end_date.nil? ||
                max_endtime < homework.course.end_date.end_of_day))
              student_work.compelete_status = 1
              student_work.cost_time = max_endtime.to_i - setting_time.publish_time.to_i
            else
              student_work.compelete_status = 0
            end
          end
        end

        efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0))
        student_work.efficiency = efficiency < 0 ? 0 : format("%.2f", efficiency)

        if homework.work_efficiency
          if homework.max_efficiency < student_work.efficiency
            # homework.max_efficiency = student_work.efficiency
            homework.update_column("max_efficiency", student_work.efficiency)
          end
          # eff_score = homework.max_efficiency == 0 ? 0 : student_work.efficiency / homework.max_efficiency * homework.eff_score
          # student_work.eff_score = format("%.2f", eff_score)
        # else
        #   student_work.eff_score = 0
        end
      elsif !compelete
        student_work.compelete_status = 0
      end
      student_work.final_score = format("%.2f", final_score.to_f)
      student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty
      score = student_work.final_score + student_work.eff_score - student_work.late_penalty
      student_work.work_score = format("%.2f", score < 0 ? 0 : score.to_f) unless student_work.ultimate_score
      student_work.save!
    end
  end

  # 计算实训作品学生的效率分
  def update_student_eff_score homework
    if homework.work_efficiency && homework.max_efficiency != 0
      homework.student_works.where("compelete_status != 0").each do |student_work|
        eff_score = student_work.efficiency / homework.max_efficiency * homework.eff_score
        student_work.eff_score = format("%.2f", eff_score)
        student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty
        unless student_work.ultimate_score
          work_score = student_work.final_score.to_f + student_work.eff_score - student_work.late_penalty
          student_work.work_score = format("%.2f", work_score < 0 ? 0 : work_score)
        end
        student_work.save!
      end
    else
      homework.student_works.where("compelete_status != 0").each do |student_work|
        student_work.eff_score = 0
        student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty
        unless student_work.ultimate_score
          work_score = student_work.final_score.to_f + student_work.eff_score - student_work.late_penalty
          student_work.work_score = format("%.2f", work_score < 0 ? 0 : work_score)
        end
        student_work.save!
      end
    end
  end

  # 用户评测时更新实训作业成绩
  def update_myshixun_work_score_old myshixun
    ActiveRecord::Base.transaction do
      student_works = myshixun.student_works.where(user_id: myshixun.user_id)
      #logger.info("#############student_works_count: #{student_works.count}")
      if student_works.count > 0
        student_works.each do |work|
          homework = work.homework_common
          #logger.info("#############member_course_group_id: #{member.try(:course_group_id)}")
          setting_time = homework.homework_group_setting work.user_id
          if setting_time.end_time.present? && (setting_time.end_time > Time.now || (homework.allow_late && homework.late_time && homework.late_time > Time.now))
            #logger.info("#############setting_time: #{setting_time.end_time}")

            user_total_score = 0
            pass_consume_time = 0
            final_score = 0
            homework.homework_challenge_settings.each do |setting|
              game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first
              unless game.nil?
                pass_consume_time += (game.cost_time / 60.0).to_f
                user_total_score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i
                adjust_score = work.challenge_work_scores.where(:challenge_id => setting.challenge_id).last
                final_score += adjust_score.present? ? adjust_score.score : (homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score > 0 ? game.real_score(setting.score) : 0))
              end
            end
            if work.work_status == 0
              is_complete = myshixun.is_complete? && (myshixun.done_time < setting_time.end_time)
              work.work_status = setting_time.end_time > Time.now ? 1 : (is_complete ? 1 : 2)
              work.late_penalty = setting_time.end_time > Time.now ? 0 : (is_complete ? 0 : homework.late_penalty)
              work.commit_time = myshixun.created_at > setting_time.publish_time ? setting_time.publish_time : myshixun.created_at
              work.myshixun_id = myshixun.id
            end

            games = myshixun.games.where(:challenge_id => homework.homework_challenge_settings.map(&:challenge_id))
            myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil
            if myshixun_endtime.present?
              min_efficiency_changed = min_efficiency_changed.present? ? min_efficiency_changed : false
              work.compelete_status = 1
              work.cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i

              efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0))
              work.efficiency = format("%.2f", efficiency)

              # 如果作业的最大效率值有变更则更新所有作品的效率分
              if homework.work_efficiency && homework.max_efficiency < work.efficiency
                homework.update_column("max_efficiency", work.efficiency)
              end
            end

            work.update_time = Time.now

            work.final_score = final_score
            score = work.final_score + work.eff_score - work.late_penalty
            work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score
            #logger.info("#############work_score: #{score}")
            work.save!
          end
        end
      end
    end
  end

  # 用户开启实训时更新作品状态
  def update_myshixun_work_status myshixun
    student_works = StudentWork.find_by_sql("SELECT sw.* FROM student_works sw, homework_commons_shixuns hcs WHERE
                                            sw.user_id = #{myshixun.user_id} AND sw.`homework_common_id` = hcs.`homework_common_id`
                                            AND hcs.`shixun_id` = #{myshixun.shixun_id} and sw.work_status = 0")
    Rails.logger.info("#############student_works_count: #{student_works.count}")
    if student_works.count > 0
      student_works.each do |work|
        homework = work.homework_common
        setting_time = homework.homework_group_setting work.user_id
        if setting_time.end_time.present? &&
            (setting_time.end_time > Time.now || (homework.allow_late && homework.late_time && homework.late_time > Time.now))

          work.work_status = setting_time.end_time > Time.now ? 1 : 2
          work.late_penalty = setting_time.end_time > Time.now ? 0 : homework.late_penalty
          work.update_time = Time.now
          work.commit_time = Time.now
          work.myshixun_id = myshixun.id
          work.save!
        end
      end
    end
  end

  # 实训作业的关卡设置
  def create_shixun_homework_cha_setting homework, shixun
    if shixun.present?
      sum_score = 0
      shixun.challenges.each_with_index do |challeng, index|
        if index < shixun.challenges.length - 1
          score = ((100.0 / shixun.challenges.length) * 100).floor / 100.0
          sum_score += score
        else
          score = 100 - sum_score
        end
        HomeworkChallengeSetting.create!(homework_common_id: homework.id, challenge_id: challeng.id,
                                        shixun_id: shixun.id, score: score)
      end
    end
  end

  # 为课堂学生创建作品
  def create_works_list homework, course
    if course.present? && CourseMember.students(course).size > 0
      str = ""
      CourseMember.students(course).each do |student|
        str += "," if str != ""
        str += "(#{homework.id},#{student.user_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')"
      end
      if str != ""
        sql = "insert into student_works (homework_common_id, user_id, created_at, updated_at) values" + str
        ActiveRecord::Base.connection.execute sql
      end
    end
  end

  # 计算实训作品成绩
  def update_myshixun_work_score work, myshixun, games, homework, challenge_settings
    user_total_score = 0
    pass_consume_time = 0
    final_score = 0
    setting_time = homework.homework_group_setting myshixun.user_id
    homework_end_or_late_time = homework.allow_late ? homework.late_time : setting_time.end_time
    games.each do |game|
      # 在截止时间前通关的关卡才考虑得分
      if game.status == 2 && game.end_time <= homework_end_or_late_time
        challenge_setting = challenge_settings.select{|setting| setting.challenge_id == game.challenge_id}.first
        pass_consume_time += (game.cost_time / 60.0).to_f
        user_total_score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i
        adjust_score = work.challenge_work_scores.select{|work_score| work_score.challenge_id == game.challenge_id}.last
        final_score += if adjust_score.present?
                         adjust_score.score
                       elsif homework.homework_detail_manual.answer_open_evaluation
                         challenge_setting.score
                       elsif game.final_score > 0
                         game.real_score(challenge_setting.score)
                       else
                         0
                       end
      end
    end

    myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil

    if work.work_status == 0
      is_complete = myshixun_endtime && (myshixun_endtime < setting_time.end_time)
      if is_complete || (myshixun.created_at < setting_time.end_time && (!homework.allow_late || setting_time.end_time >= Time.now))
        work.work_status = 1
      elsif homework.allow_late && myshixun.created_at < homework.late_time
        work.work_status = 2
      end
    end

    if work.work_status != 0
      if myshixun_endtime.present?
        work.cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i

        efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0))
        work.efficiency = format("%.2f", efficiency)

        if myshixun_endtime <= homework_end_or_late_time
          work.compelete_status = myshixun_endtime < setting_time.publish_time ? 2 : 1

          # 如果作业的最大效率值有变更则更新所有作品的效率分
          homework.update_column("max_efficiency", work.efficiency) if homework.work_efficiency && homework.max_efficiency < work.efficiency
        end
      end

      work.late_penalty = work.work_status == 2 ? homework.late_penalty : 0
      work.commit_time = myshixun.created_at > setting_time.publish_time ? setting_time.publish_time : myshixun.created_at
      work.myshixun_id = myshixun.id
      work.update_time = myshixun.updated_at

      work.final_score = final_score
      score = work.final_score + work.eff_score - work.late_penalty
      work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score
      #logger.info("#############work_score: #{score}")
      work.calculation_time = Time.now
      work.save!
    end
  end
end