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, answer_public: true) #实训作业参考答案默认公开

      homework_detail_manual = HomeworkDetailManual.new
      homework.homework_detail_manual = homework_detail_manual
      homework.position = course.practice_homeworks.first&.position.to_i + 1

      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
      max_efficiency = homework.student_works.where("compelete_status > 0").pluck(:efficiency).max
      homework.update_column("max_efficiency", max_efficiency)
      homework.student_works.where("compelete_status > 0").each do |student_work|
        eff_score = max_efficiency.to_f == 0 ? 0 : (student_work.efficiency / max_efficiency.to_f * homework.eff_score)
        late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty.to_f
        unless student_work.ultimate_score
          work_score = student_work.final_score.to_f + eff_score.to_f - late_penalty
          work_score = format("%.2f", work_score < 0 ? 0 : work_score)
        end
        eff_score = format("%.2f", eff_score).to_f
        student_work.update_columns(eff_score: eff_score, late_penalty: late_penalty, work_score: work_score)
      end
    else
      homework.student_works.where("compelete_status > 0").each do |student_work|
        eff_score = 0
        late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty.to_f
        unless student_work.ultimate_score
          work_score = student_work.final_score.to_f - late_penalty
          work_score = format("%.2f", work_score < 0 ? 0 : work_score).to_f
        end
        student_work.update_columns(eff_score: eff_score, late_penalty: late_penalty, work_score: work_score)
      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

  # 计算实训作品成绩,更新单个作品的成绩
  # work: student_work
  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
      else
        adjust_score = work.challenge_work_scores.select{|work_score| work_score.challenge_id == game.challenge_id}.last
        final_score += adjust_score.score if adjust_score.present?
      end
    end

    # game#status 0：已开启；1：正在评测；2：通过评测；3：锁定
    # 最后通关时间,没有通关则为空
    myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil
    # 是否在指定时间内通关
    is_complete = myshixun_endtime && (myshixun_endtime < setting_time.end_time)

    # if work.work_status == 0
    #   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 homework.allow_late && setting_time.end_time <= Time.now && !is_complete
      work.work_status = 2
    else
      work.work_status = 1
    end

    if work.work_status != 0
      if myshixun_endtime.present?
        work_cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i
        work.cost_time = work_cost_time > 0 ? work_cost_time : games.select{|game| game.status == 2}.pluck(:cost_time).sum
        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
          # 2是按时通关， 3是迟交通关
          work.compelete_status = myshixun_endtime < setting_time.end_time ? 2 : 3

          # 如果作业的最大效率值有变更则更新所有作品的效率分
          if homework.work_efficiency && homework.max_efficiency < work.efficiency
            homework.max_efficiency = work.efficiency
            homework.save(validate: false)
          end
        else
          work.compelete_status = 1 # 未通关
        end
      else
        work.compelete_status = 1 # 未通关
      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 = if myshixun_endtime.present? && myshixun_endtime <= homework_end_or_late_time
                           myshixun_endtime
                         elsif myshixun.updated_at > homework_end_or_late_time
                           last_pass_time = games.select{|game| game.status == 2 && game.end_time < homework_end_or_late_time}.map(&:end_time).max
                           last_pass_time.present? ? last_pass_time : myshixun.created_at
                         else
                           myshixun.updated_at
                         end

      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(validate: false)
    end
  end

  # 该方法返回单个作品的成绩分数，最后批量更新实训成绩来提高数据处理速度
  def batch_update_myshixun_work_score myshixun, games, homework, challenge_settings, challenge_work_scores
    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|
      adjust_score = challenge_work_scores.select { |d| d.challenge_id == game.challenge_id && d.student_work_id == myshixun['student_work_id']}.last
      # 在截止时间前通关的关卡才考虑得分 ?
      # game#status 0：已开启；1：正在评测；2：通过评测；3：锁定
      if game.status == 2 && game.end_time <= homework_end_or_late_time
        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
        final_score += if adjust_score.present?
                         adjust_score.score
                       elsif homework.homework_detail_manual.answer_open_evaluation
                         challenge_settings[game.challenge_id]
                       elsif game.final_score > 0
                         game.real_score_from_challenge(challenge_settings[game.challenge_id], game['challenge_score'])
                       else
                         0
                       end
      else
        final_score += adjust_score.score if adjust_score.present?
      end
    end

    # 实训所有关卡都完成后的结束时间, 没完成则置为没空
    myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil

    # 过了允许迟交的结束时间后未在指定时间内通关的，作业状态视为迟交
    if homework.allow_late && setting_time.end_time <= Time.now && !(myshixun_endtime && (myshixun_endtime < setting_time.end_time))
      myshixun['work_status'] = 2
    else
      myshixun['work_status'] = 1
    end

    if myshixun_endtime.present?
      work_cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i
      myshixun['cost_time'] = work_cost_time > 0 ? work_cost_time : games.where(status: 0).sum(:cost_time)
      myshixun['efficiency'] = format("%.2f", (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0)))

      if myshixun_endtime <= homework_end_or_late_time
        # compelete_status 实训作业完成状态: -1重做中 0未开启 1未通关 2按时通关 3迟交通关
        myshixun['compelete_status'] = myshixun_endtime < setting_time.end_time ? 2 : 3

        # 如果作业的最大效率值有变更则更新所有作品的效率分
        if homework.work_efficiency && homework.max_efficiency < myshixun['efficiency'].to_f
          homework.max_efficiency = myshixun['efficiency']
          homework.save(validate: false)
        end
      else
        myshixun['compelete_status'] = 1 # 未通关
      end
    else
      myshixun['compelete_status'] = 1 # 未通关
    end

    myshixun['late_penalty'] = myshixun['work_status'] == 2 ? homework.late_penalty : 0
    myshixun['commit_time'] = myshixun.created_at > setting_time.publish_time ? setting_time.publish_time : myshixun.created_at
    myshixun['myshixun_id'] = myshixun.id
    myshixun['update_time'] = if myshixun_endtime.present? && myshixun_endtime <= homework_end_or_late_time
                                myshixun_endtime
                              elsif myshixun.updated_at > homework_end_or_late_time
                                last_pass_time = games.select{|game| game.status == 2 && game.end_time < homework_end_or_late_time}.map(&:end_time).max
                                last_pass_time.present? ? last_pass_time : myshixun.created_at
                              else
                                myshixun.updated_at
                              end

    myshixun['final_score'] = final_score
    
    if myshixun['ultimate_score'] == 0 # 一个坑，如果设置ultimate_score为false，是返回0
      score = myshixun['final_score'].to_f + myshixun['eff_score'].to_f - myshixun['late_penalty'].to_f
      myshixun['work_score'] = format("%.2f",(score < 0 ? 0 : score).to_f)
    end
    myshixun['calculation_time'] = Time.now

    {
      compelete_status: myshixun['compelete_status'],
      work_status: myshixun['work_status'],
      efficiency: myshixun['efficiency'],
      late_penalty: myshixun['late_penalty'],
      commit_time: "'#{myshixun['commit_time']}'",
      myshixun_id: myshixun['myshixun_id'],
      update_time: "'#{myshixun['update_time']}'",
      final_score: myshixun['final_score'],
      work_score: myshixun['work_score'],
      calculation_time: "'#{myshixun['calculation_time']}'",
    }
  end
end