class ExercisesController < ApplicationController
  before_action :require_login, :check_auth, except: [:index]
  before_action :find_course, only: [:index, :new, :create, :my_exercises, :public_exercises, :set_public, :destroys,
                                     :join_exercise_banks, :publish_modal, :publish, :end_modal, :end_exercise] #需要有课堂id参数的
  before_action :get_exercise, except: [:index, :new, :create, :my_exercises, :public_exercises, :set_public, :destroys,
                                        :join_exercise_banks, :publish_modal, :publish, :end_modal, :end_exercise]
  before_action :user_course_identity
  before_action :is_course_teacher, except: [:index, :start_answer, :exercise_setting, :commit_exercise, :exercise_lists, :review_exercise,
                                             :exercise_result, :common_header, :cancel_exercise, :begin_commit]
  before_action :get_left_banner_id, only: [:common_header, :start_answer, :review_exercise, :review_exercises_by_students, :index, :new, :edit]
  before_action :validates_exercise_params, only: [:create, :update]
  before_action :get_exercise_question_counts, only: [:show, :edit, :start_answer, :review_exercise, :review_exercises_by_students, :blank_exercise, :export_exercise]
  before_action :validate_publish_time, only: [:commit_setting] #提交设置时，需判断时间是否符合
  before_action :check_course_public, only: [:set_public]
  before_action :check_user_on_answer, only: [:show, :start_answer, :exercise_lists] #判断当前用户在试卷的权限/老师是否属于分班的权限
  before_action :only_student_in, only: [:start_answer]
  before_action :check_user_id_start_answer, only: [:start_answer, :review_exercise]
  # before_action :commit_user_exercise,only: [:start_answer,:exercise_lists,:review_exercise]   #已有定时的任务
  before_action :check_exercise_time, only: [:commit_exercise] #提交试卷时，判断时间是否超过
  before_action :check_exercise_status, only: [:redo_modal, :redo_exercise]
  before_action :check_exercise_is_end, only: [:review_exercise]
  before_action :check_exercise_public, only: [:exercise_result] #试卷是否为公开
  before_action :commit_shixun_present, only: [:commit_shixun]
  before_action :update_reviewed_status, only: [:review_exercise, :review_exercises_by_students]
  before_action :get_exercise_users_list, only: [:exercise_lists] # 答题列表页答题列表
  include ExportHelper
  include ExercisesHelper

  # model validation error
  rescue_from ActiveRecord::RecordInvalid do |ex|
    render_error(ex.record.errors.full_messages.join(','))
  end
  # form validation error
  rescue_from ActiveModel::ValidationError do |ex|
    render_error(ex.model.errors.full_messages.join(','))
  end

  def index
    begin
      # 按发布时间或创建时间排序
      @exercises_all = @course.exercises
      member_show_exercises = @exercises_all.is_exercise_published #已发布的或已截止的试卷
      @current_user_ = current_user

      # 课堂的学生人数
      @course_all_members = @course.students #当前课堂的全部学生
      @current_student = @course_all_members.course_find_by_ids("user_id", current_user.id) #当前用户是否为课堂的学生

      # exercises的不同用户群体的显示
      if @user_course_identity < Course::STUDENT # @is_teacher_or 1为老师/管理员/助教
        @is_teacher_or = 1
        @exercises = @exercises_all #老师能看到全部的试卷，不管是已发布的/未发布的/已截止的/统一设置的/私有设置的（看到内容不同）
      elsif @user_course_identity == Course::STUDENT # 2为课堂成员，能看到统一设置的和自己班级的
        @is_teacher_or = 2
        @member_group_id = @current_student.first.try(:course_group_id).to_i # 成员的分班id，默认为0
        if @member_group_id == 0 #表示是课堂的未分班成员,只能查看统一设置的试卷（已发布的/已截止的）
          @exercises = member_show_exercises.exists? ? member_show_exercises.unified_setting : []
        else #已分班级的成员，可以查看统一设置和单独设置（试卷是发布在该班级）试卷
          # 已发布 当前用户班级分组的 试卷id
          publish_exercise_ids = @course.exercise_group_settings.exercise_group_published.where("course_group_id = #{@member_group_id}").pluck(:exercise_id)
          @exercises = member_show_exercises.unified_setting.or(member_show_exercises.where(id: publish_exercise_ids))
        end
      else #用户未登陆或不是该课堂成员,仅显示统一设置的（已发布的/已截止的），如有公开，则不显示锁，不公开，则显示锁
        @is_teacher_or = 0
        @exercises = member_show_exercises.unified_setting
      end

      if @exercises.size > 0
        if params[:type].present?
          choose_type = params[:type].to_i
          ex_setting_ids = []
          if @is_teacher_or != 2
            @exercises = @exercises.where("exercise_status = #{choose_type}")
          else
            case choose_type
            when 1
              ex_setting_ids = @course.exercise_group_settings.where("course_group_id = #{@member_group_id}").exercise_group_not_published.pluck(:exercise_id)
            when 2
              ex_setting_ids = @course.exercise_group_settings.where("course_group_id = #{@member_group_id}")
                                 .where("publish_time is not null and publish_time <= ? and end_time > ?", Time.now, Time.now).pluck(:exercise_id)
            when 3
              ex_setting_ids = @course.exercise_group_settings.where("course_group_id = #{@member_group_id}").exercise_group_ended.pluck(:exercise_id)
            end
            unified_setting_ids = @exercises.unified_setting.where("exercise_status = #{choose_type}").pluck(:id)
            ex_ids = (ex_setting_ids + unified_setting_ids).uniq
            @exercises = @exercises.where(id: ex_ids)
          end
        end

        if params[:search].present?
          search_type = params[:search].to_s.strip
          @exercises = @exercises.exercise_search(search_type)
        end

        @exercises_select_count = @exercises.size # 全部页面，需返回
        # 一级排序：提交中、已截止、未发布，二级排序：发布时间倒序
        @exercises = @exercises.distinct.
            order(Arel.sql("field(exercise_status, #{Exercise::PUBLISHED}, #{Exercise::DEADLINE}, #{Exercise::UNPUBLISHED})")).
            order("publish_time desc")

        # 分页
        @page = params[:page] || 1
        @limit = params[:limit] || 15
        @exercises = @exercises.page(@page).per(@limit)
        @exercises = @exercises&.includes(:published_settings)
      else
        @exercises = []
      end

      @course_all_members_count = @course_all_members.size #当前课堂的学生数
      @exercises_count = @exercises_all.size # 全部页面，需返回
      @exercises_unpublish_counts = @exercises_all.exercise_by_status(1).size #未发布的试卷数
      @exercises_published_counts = @exercises_count - @exercises_unpublish_counts # 已发布的试卷数,包含已截止的

    rescue Exception => e
      uid_logger_error(e.message)
      tip_exception(e.message)
      raise ActiveRecord::Rollback
    end
  end

  def new
    ActiveRecord::Base.transaction do
      begin
        @exercise = Exercise.new
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception("试卷创建失败！")
        raise ActiveRecord::Rollback
      end
    end
  end

  def create
    ActiveRecord::Base.transaction do
      ex_name = params[:exercise_name]
      ex_desc = params[:exercise_description]
      exercise_options = {
        :exercise_name => ex_name,
        :exercise_description => ex_desc,
        :user_id => current_user.id,
        :course_id => @course.id,
        :time => -1,
        :exercise_status => 1,
        :is_md => params[:is_md]
      }
      @exercise = Exercise.create!(exercise_options)
    end
  end

  #试卷的内容，及试题/答案的内容编辑
  def edit
    ActiveRecord::Base.transaction do
      if @exercise.is_random?
        @exercise_score_settings = @exercise.exercise_score_settings
        @exercise_random_settings = @exercise.exercise_random_settings.includes(:sub_discipline=>[:discipline])
      else
        @exercise_questions = @exercise.exercise_questions.includes(:hack).order("question_number ASC")
      end
    end
  end

  def update
    ActiveRecord::Base.transaction do
      params.permit!
      ex_name = params[:exercise_name]
      ex_desc = params[:exercise_description]
      exercise_options = {
        :exercise_name => ex_name,
        :exercise_description => ex_desc,
      }
      @exercise.update!(exercise_options)
      if @exercise.exercise_status != Exercise::PUBLISHED
        @exercise.exercise_score_settings.destroy_all
        @exercise.exercise_random_settings.destroy_all
        @exercise.update!(params.slice(:difficulty, :time, :source))
        if @exercise.save!
          if @exercise.is_random?
            params[:contents].each do |random_setting|
              @exercise.exercise_random_settings.create!(
                  item_type: random_setting[:item_type],
                  sub_discipline_id: random_setting[:sub_discipline_id],
                  difficulty: random_setting[:difficulty],
                  quanlity: random_setting[:items_count]
              )
            end
            params[:score_settings].each do |score_setting|
              @exercise.exercise_score_settings.create!(
                  item_type: score_setting[:item_type], score: score_setting[:score]
              )
            end
          end
        end
      end
      normal_status(0, "试卷更新成功！")
    end
  end

  def show
    ActiveRecord::Base.transaction do
      if @user_course_identity < Course::STUDENT
        @is_teacher_or = 1 #为老师/助教/管理员
      else
        @is_teacher_or = 0 #为学生
      end
      @exercise_questions = @exercise.exercise_questions&.includes(:exercise_choices, :exercise_shixun_challenges, :exercise_standard_answers).order("question_number ASC")
    end
  end

  #试卷的公用头部
  def common_header
    ActiveRecord::Base.transaction do
      @user_left_time = nil
      if @user_course_identity > Course::ASSISTANT_PROFESSOR
        @is_teacher_or = 0
        @user_exercise_answer = @exercise.check_user_answer_status(current_user)
        @user_commit_counts = 0
        @user_left_time = get_exercise_left_time(@exercise, current_user)
      else
        @is_teacher_or = 1
        @user_exercise_answer = 3 #教师页面
        @user_commit_counts = @exercise.exercise_users.
            where(commit_status: [ExerciseUser.commit_statuses[:commited], ExerciseUser.commit_statuses[:commit_with_no_answer]]).size #已提交的用户数
      end
      @ex_status = @exercise.get_exercise_status(current_user)

      exercise_id_array = [@exercise.id]
      @exercise_publish_count = get_user_permission_course(exercise_id_array, Exercise::PUBLISHED).size #是否存在已发布的
      @exercise_unpublish_count = get_user_permission_course(exercise_id_array, Exercise::UNPUBLISHED).size #是否存在未发布的

      if (@exercise_publish_count == 0) && (@exercise_unpublish_count == 0) #即表示没有分班
        if @ex_status == Exercise::UNPUBLISHED
          @exercise_unpublish_count = 1 #试卷未发布，且课堂没有分班的时候
        elsif @ex_status == Exercise::PUBLISHED
          @exercise_publish_count = 1 #试卷未发布，且课堂没有分班的时候
        end
      end
    end
  end

  #实训题目的选用
  def choose_shixun
    ActiveRecord::Base.transaction do
      search = params[:search]
      if @user_course_identity > Course::ADMIN #当不为管理员的时候
        user_school_id = current_user.school_id #当前用户的学校id
        if user_school_id.present?
          none_shixun_ids = ShixunSchool.where("school_id != #{user_school_id}").pluck(:shixun_id)
          @publish_shixuns = Shixun.where.not(id: none_shixun_ids).unhidden
        end
      else
        @publish_shixuns = Shixun.unhidden
      end
      if search.present?
        @publish_shixuns = @publish_shixuns.search_by_name(search)
      end

      @shixuns = @publish_shixuns.joins(:challenges).where("challenges.st != 0").distinct
      # 全部页面，需返回
      @shixuns_count = @shixuns.count

      # 分页
      @page = params[:page] || 1
      @limit = params[:limit] || 8

      @shixuns = @shixuns.page(@page).per(@limit)
    end
  end

  #确认实训的选择
  def commit_shixun
    ActiveRecord::Base.transaction do
      @shixun_challenges = @shixun.challenges
      @shixun_challenges_count = @shixun_challenges.size
    end
  end

  # 首页批量或单独删除
  def destroys
    ActiveRecord::Base.transaction do
      check_ids = Exercise.where(id: params[:check_ids])
      check_ids.destroy_all
      normal_status(0, "试卷已删除成功！")
    end
  end

  # 设为公开
  def set_public
    ActiveRecord::Base.transaction do
      check_ids = Exercise.where(id: params[:check_ids])
      check_ids.each do |exercise|
        exercise.update!(is_public: true)
      end
      normal_status(0, "试卷已设为公开！")
    end
  end

  ## 加入题库
  def join_exercise_banks
    ActiveRecord::Base.transaction do
      check_ids = Exercise.where(id: params[:check_ids])
      exam_message = ""
      check_ids.each do |exercise|
        tip_exception(-1, "随机试卷无法加入题库") if exercise.is_random?
        if exercise.examination_bank_id.present? && exercise.exercise_questions.where(question_type: Exercise::PROGRAM).size > 0
          exam_message = "，编程题暂不支持发送到题库"
        end
        current_ex_bank = current_user.exercise_banks.find_by_container(exercise.id, "Exercise")&.first
        if current_ex_bank.present? #当前用户的选择试卷是否已加入习题库，存在则更新习题库和问题库，否则新建习题库和问题库
          ex_params = {
            :name => exercise.exercise_name,
            :description => exercise.exercise_description,
            :course_list_id => exercise.course.try(:course_list_id)
          }
          current_ex_bank.update!(ex_params)
          # question_bank = QuestionBank.ques_by_container(current_ex_bank.id,current_ex_bank.container_type).first  #该习题库是否存在于问题库里
          # ques_params = {
          #     :name => current_ex_bank.name,
          #     :course_list_id => current_ex_bank.course_list_id
          # }
          # question_bank.update_attributes(ques_params) if question_bank.present?
          current_ex_bank.exercise_bank_questions.destroy_all # 更新后，习题库的问题全部删除，后续重新再建
        else
          ex_params = {
            :name => exercise.exercise_name,
            :description => exercise.exercise_description,
            :user_id => current_user.id,
            :is_public => 0,
            :course_list_id => exercise.course.try(:course_list_id),
            :container_id => exercise.id,
            :container_type => "Exercise",
            :quotes => 1
          }
          current_ex_bank = ExerciseBank.new ex_params
          current_ex_bank.save! #如果习题库保存成功，则会创建问题库question_bank
          # if current_ex_bank.save
          #   ques_params = {
          #       :name => current_ex_bank.name,
          #       :container_id => current_ex_bank.id,
          #       :container_type => current_ex_bank.container_type,
          #       :quotes => current_ex_bank.quotes,
          #       :user_id => current_ex_bank.user_id,
          #       :is_public => current_ex_bank.is_public,
          #       :course_list_id => current_ex_bank.course_list_id
          #   }
          #   question_bank = QuestionBank.new ques_params
          #   question_bank.save
          # end
          exercise.update!(exercise_bank_id: current_ex_bank.id)
        end
        # 对于随机试卷，只需将随机规则复制过来即可
        if exercise.is_random?
          # 如果是随机组卷的话，仅仅需要将随机规则发送过去
          exercise.exercise_random_settings.each do |exercise_random_setting|
            current_ex_bank.exercise_bank_random_settings.create!(
                difficulty: exercise_random_setting.difficulty,
                sub_discipline_id: exercise_random_setting.sub_discipline_id,
                quanlity: exercise_random_setting.quanlity,
                item_type: exercise_random_setting.item_type
            )
          end
          # 赋分规则
          exercise.exercise_score_settings.each do |exercise_score_setting|
            current_ex_bank.exercise_bank_score_settings.create!(
                item_type: exercise_score_setting.item_type,
                score: exercise_score_setting.score
            )
          end
        else
          # 试卷的问题的输入
          exercise.exercise_questions.where.not(question_type: Exercise::PROGRAM).each do |q|
            option = {
                :question_title => q.question_title,
                :question_type => q.question_type,
                :question_number => q.question_number,
                :question_score => q.question_score,
                :shixun_id => q.shixun_id,
                :shixun_name => q.shixun_name,
                :is_ordered => q.is_ordered
            }
            exercise_bank_question = current_ex_bank.exercise_bank_questions.new option
            exercise_bank_question.save!
            ## 试卷选项的输入
            if q.question_type != Exercise::PRACTICAL #不为实训题时,试卷选项加入试题答案库
              ex_choices = q.exercise_choices
              ex_standard = q.exercise_standard_answers
              ex_choices.each do |c|
                choice_option = {
                    :choice_position => c.choice_position,
                    :choice_text => c.choice_text
                }
                ex_bank_choice = exercise_bank_question.exercise_bank_choices.new choice_option
                ex_bank_choice.save!
              end
              ex_standard.each do |s|
                ex_stand = {
                    :exercise_bank_choice_id => s.exercise_choice_id,
                    :answer_text => s.answer_text
                }
                ex_stand_bank = exercise_bank_question.exercise_bank_standard_answers.new ex_stand
                ex_stand_bank.save!
              end
            else #当为实训题时
              shixun_challenges = q.exercise_shixun_challenges
              shixun_challenges.each do |c|
                challenge_option = {
                    :position => c.position,
                    :challenge_id => c.challenge_id,
                    :shixun_id => q.shixun_id,
                    :question_score => c.question_score
                }
                shixun_challenge_bank = exercise_bank_question.exercise_bank_shixun_challenges.new challenge_option
                shixun_challenge_bank.save!
              end
            end
          end
        end
        current_ex_bank.save!
      end
      message = "题库更新成功"
      message += exam_message.to_s if exam_message.present?
      normal_status(0, message)
    end
  end

  #试卷的设置页面
  def exercise_setting
    ActiveRecord::Base.transaction do
      @user_permission = 2
      @user_course_groups = @course.teacher_group(current_user.id) #当前老师的分班
      @being_setting_course_ids = @exercise.common_published_ids(current_user.id) #当前用户已发布的班级的id
      @user_published_setting = @exercise.exercise_group_settings
                                  .find_in_exercise_group("course_group_id", @being_setting_course_ids) #当前用户已发布班级的试卷设置
      exercise_ids = [@exercise.id]
      @exercise_publish_count = get_user_permission_course(exercise_ids, Exercise::PUBLISHED).count #判断当前用户是否有试卷已发布的分班，用于显示立即截止/撤销发布
      @exercise_unpublish_count = get_user_permission_course(exercise_ids, Exercise::UNPUBLISHED).count #判断当前用户是否有试卷未发布的分班，用户显示立即发布
      @exercise_users_count = @exercise.exercise_users.commit_exercise_by_status(1).count #判断当前试卷是否有已提交的
      # ## 需添加发送消息的接口，稍后添加
    end
  end

  #试卷的提交设置
  def commit_setting
    tip_exception("助教无权限修改本试卷") if @user_course_identity == Course::ASSISTANT_PROFESSOR && !@exercise.assistant_auth
    ActiveRecord::Base.transaction do
      error_count = 0 # 判断循环里是否有已发布/已截止的，且时间更改了的分班。
      # course_group_ids = @course.teacher_course_group_ids(current_user.id)  #当前老师的班级id数组
      course_group_ids = @course.charge_group_ids(current_user) #当前老师的班级id数组

      exercise_status = @exercise.get_exercise_status(current_user)

      if exercise_status == Exercise::UNPUBLISHED && course_group_ids.size > 0 # 试卷未发布，且老师的分班大于1 ，才可以修改统一设置，否则按试卷默认的来处理
        unified_setting = params[:unified_setting]
      else
        unified_setting = @exercise.unified_setting
      end

      show_statistic = params[:show_statistic] ? true : false
      exercise_time = params[:time].blank? ? -1 : params[:time]
      question_random = params[:question_random] ? true : false #问题是否随机，0为不随机，1为随机
      choice_random = params[:choice_random] ? true : false
      score_open = params[:score_open] ? true : false #分数是否公开
      answer_open = params[:answer_open] ? true : false #答案是否公开
      assistant_auth = params[:assistant_auth] # 助教权限

      # 统一设置或者分班为0，则更新试卷，并删除试卷分组
      if unified_setting || (course_group_ids.size == 0)
        tip_exception("发布时间不能为空") if params[:publish_time].blank?
        tip_exception("截止时间不能为空") if params[:end_time].blank?
        tip_exception("截止时间必须晚于发布时间") if params[:publish_time].to_time >= params[:end_time].to_time
        tip_exception("截止时间不能晚于课堂结束时间（#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}）") if @course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day

        params_publish_time = params[:publish_time].to_time
        params_end_time = params[:end_time].to_time

        if (exercise_status != Exercise::UNPUBLISHED) && (@exercise.publish_time != params_publish_time)
          normal_status(-1, "已发布/已截止,不允许修改发布时间")
        elsif params_publish_time.present? && params_end_time.present? && params_end_time < params_publish_time
          normal_status(-1, "截止时间不能小于发布时间")
        else
          # 如果试卷由已截止状态变更为考试中,则需要将所有已交卷未答的用户的提交状态调整为未提交
          #发布时间小于当前时间，则试卷显示为未发布,当截止时间大于当前时间，则显示为已截止
          exercise_status_n = set_exercise_status(params_publish_time, params_end_time)
          if exercise_status_n == Exercise::PUBLISHED && @exercise.exercise_status == Exercise::DEADLINE
            exercise_users = @exercise.exercise_users.commit_with_no_answer
            exercise_users.update_all(
                :score => 0.0,
                :start_at => nil,
                :end_at => nil,
                :status => nil,
                :commit_status => ExerciseUser.commit_statuses[:none_commit],
                :objective_score => 0.0,
                :subjective_score => -1.0,
                :commit_method => 0,
                :reviewed => 0,
                :subjective_reviewed => 0
            )
            @exercise.exercise_answers.where(user_id: exercise_users.pluck(:user_id)).destroy_all
            @exercise.exercise_shixun_answers.where(user_id: exercise_users.pluck(:user_id)).destroy_all
          end
          exercise_params = {
            :unified_setting => unified_setting,
            :show_statistic => show_statistic,
            :time => exercise_time,
            :question_random => question_random,
            :choice_random => choice_random,
            :score_open => score_open,
            :answer_open => answer_open,
            :exercise_status => exercise_status_n,
            :publish_time => params_publish_time,
            :end_time => params_end_time,
            :assistant_auth => assistant_auth
          }
          @exercise.update!(exercise_params)
          @exercise.exercise_group_settings.destroy_all
          normal_status(0, "试卷设置成功！")
        end
      else
        params_times = params[:publish_time_groups] #分班返回的json数组{"publish_time_groups":[{"course_group_id":"1","publish_time":"xx","end_time":"xxx"}]}
        exercise_groups = @exercise.exercise_group_settings.find_in_exercise_group("course_id", @course.id) #试卷的全部分班信息
        exercise_groups_ids = exercise_groups.pluck(:course_group_id) #问卷的全部分班id
        total_common = params_times.map {|k| k[:course_group_id]}.sum.uniq #传入的所有分组的分班id
        total_common_group = exercise_groups_ids & total_common #传入的分班与问卷已存在的分班的交集
        old_exercise_groups = exercise_groups_ids - total_common_group #后来传入的分班里，没有了的班级，即需要删除

        params_times.each do |t|
          tip_exception("发布时间不能为空") if t[:publish_time].blank?
          tip_exception("截止时间不能为空") if t[:end_time].blank?
          tip_exception("截止时间不能早于发布时间") if t[:publish_time].to_time > t[:end_time].to_time
          tip_exception("截止时间不能晚于课堂结束时间（#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}）") if @course.end_date.present? && t[:end_time].to_time > @course.end_date.end_of_day

          course_id = t[:course_group_id]
          exercise_publish_time = t[:publish_time].to_time
          exercise_end_time = t[:end_time].to_time

          exercise_group = exercise_groups.where(course_group_id: course_id) #判断该分班是否存在
          if exercise_group.present? && (exercise_group.first.publish_time < Time.now) && (exercise_publish_time != exercise_group.first.publish_time)
            error_count += 1
          end
          if exercise_group.present? && (exercise_group.first.publish_time < Time.now && exercise_group.first.end_time > Time.now) && (exercise_end_time < Time.now)
            error_count += 1
          end
          if error_count == 0
            common_group = exercise_groups_ids & course_id #传入的班级与问卷已存在的班级的交集，即表示已有分班的
            new_group_ids = course_id - common_group #新传入的班级id
            if common_group.count > 0 #判断试卷的分班设置是否存在，存在则更新，负责则新建
              exercise_group_sets = exercise_groups.where(course_group_id: common_group)
              exercise_group_sets.each do |the_group_setting|
                ex_group_params = {
                  :publish_time => exercise_publish_time,
                  :end_time => exercise_end_time
                }

                # 原先的该分班的状态
                the_group_setting_status = set_exercise_status(the_group_setting.publish_time, the_group_setting.end_time)
                # 按照新的分班设置的时间的状态
                new_group_setting_status = set_exercise_status(the_group_setting.publish_time, exercise_end_time)
                # 如果该分班因为修改截止时间导致试卷由已截止变更为考试中,则需要将该分班下对应的学生也打回变更为未开始
                if the_group_setting_status == Exercise::DEADLINE && new_group_setting_status == Exercise::PUBLISHED
                  exercise_users = @exercise.exercise_users.commit_with_no_answer.
                  joins("join course_members on exercise_users.user_id=course_members.user_id").
                  where(course_members: {course_group_id: the_group_setting.course_group_id})
                  exercise_users.update_all(
                      :score => 0.0,
                      :start_at => nil,
                      :end_at => nil,
                      :status => nil,
                      :commit_status => ExerciseUser.commit_statuses[:none_commit],
                      :objective_score => 0.0,
                      :subjective_score => -1.0,
                      :commit_method => 0,
                      :reviewed => 0,
                      :subjective_reviewed => 0
                  )
                  @exercise.exercise_answers.where(user_id: exercise_users.pluck(:user_id)).destroy_all
                  @exercise.exercise_shixun_answers.where(user_id: exercise_users.pluck(:user_id)).destroy_all
                end
                if the_group_setting_status == Exercise::PUBLISHED
                  ex_group_params = {
                    :publish_time => the_group_setting.publish_time,
                    :end_time => exercise_end_time < Time.now ? the_group_setting.end_time : exercise_end_time
                  }
                elsif the_group_setting_status == Exercise::DEADLINE
                  ex_group_params = {
                    :publish_time => the_group_setting.publish_time,
                    :end_time => exercise_end_time
                  }
                end
                the_group_setting.update!(ex_group_params)
              end
            end
            if new_group_ids.size > 0
              new_group_ids.each do |c|
                exercise_group_params = {
                  :exercise_id => @exercise.id,
                  :course_group_id => c,
                  :course_id => @course.id,
                  :publish_time => exercise_publish_time,
                  :end_time => exercise_end_time
                }
                new_exercise_group = ExerciseGroupSetting.new(exercise_group_params)
                new_exercise_group.save!
              end
            end
          end
        end

        if error_count > 0
          error_count == 0
          normal_status(-1, "试卷发布/截止时间不能小于当前时间")
        else
          # 未发布的分班设置才能删除
          if old_exercise_groups.size > 0
            old_all_ex_groups = exercise_groups.find_in_exercise_group("course_group_id", old_exercise_groups).exercise_group_not_published
            old_all_ex_groups.destroy_all
          end
          #试卷更新为exercise_group_setting的发布时间最小，截止时间最大
          e_time_present = exercise_groups.end_time_no_null.map(&:end_time)
          p_time_present = exercise_groups.publish_time_no_null.map(&:publish_time)
          e_time = e_time_present.size > 0 ? e_time_present.max : nil
          p_time = p_time_present.size > 0 ? p_time_present.min : nil
          exercise_status = 1
          if p_time.nil? #发布时间为空，则表示问卷未发布
            exercise_status = 1
          elsif p_time.present? && e_time.present?
            exercise_status = set_exercise_status(p_time, e_time)
          end
          exercise_params = {
            :unified_setting => unified_setting,
            :show_statistic => show_statistic,
            :time => exercise_time,
            :question_random => question_random,
            :choice_random => choice_random,
            :score_open => score_open,
            :answer_open => answer_open,
            :exercise_status => exercise_status,
            :publish_time => p_time,
            :end_time => e_time,
            :assistant_auth => assistant_auth
          }
          @exercise.update!(exercise_params)
          if @exercise.exercise_status == Exercise::PUBLISHED
            if @exercise.course_acts.size == 0
              @exercise.course_acts << CourseActivity.new(:user_id => @exercise.user_id, :course_id => @exercise.course_id)
            end
          end
          normal_status(0, "试卷设置成功！")
        end
      end
    end
  end

  # 对未提交、已交卷未答、已交卷已答的用户的整张试卷进行调分
  def adjust_score
    exercise_user = @exercise.exercise_users.find_by!(user_id: params[:user_id])
    tip_exception("未交卷/考试中的用户不可评阅") if exercise_user.none_commit?
    tip_exception("已提交的作品请去评阅页进行调分") if exercise_user.commited? && !exercise_user.adjust_by_teacher?
    if @exercise.subjective_score > 0
      tip_exception("主观题成绩不能为空") if params[:subjective_score].blank?
      tip_exception("主观题成绩不能小于零") if params[:subjective_score].to_f < 0
      tip_exception("主观题成绩不能大于总分值：#{@exercise.subjective_score}分") if params[:subjective_score].to_f.round(1) > @exercise.subjective_score.round(1)
    end

    if @exercise.objective_score > 0
      tip_exception("客观题成绩不能为空") if params[:objective_score].blank?
      tip_exception("客观题成绩不能小于零") if params[:objective_score].to_f < 0
      tip_exception("客观题成绩不能大于总分值：#{@exercise.objective_score}分") if params[:objective_score].to_f.round(1) > @exercise.objective_score.round(1)
    end

    ActiveRecord::Base.transaction do
      start_at_time = exercise_user.start_at || Time.now
      subjective_score = @exercise.subjective_score > 0 ? params[:subjective_score].to_f.round(2) : 0
      objective_score = @exercise.objective_score > 0 ? params[:objective_score].to_f.round(2) : 0
      score = subjective_score + objective_score
      reviewed = true
      subjective_reviewed = exercise_user.subjective_reviewed || @exercise.subjective_score > 0 && params[:subjective_score].present?
      if exercise_user.commited? || exercise_user.commit_with_no_answer?
        exercise_user.update!(score: score, subjective_score: subjective_score, objective_score: objective_score,
                              reviewed: reviewed, subjective_reviewed: subjective_reviewed)
      else
        if @exercise.exercise_answers.where(user_id: exercise_user.user_id).blank? && @exercise.exercise_shixun_answers.where(user_id: exercise_user.user_id).blank?
          commit_status = "commit_with_no_answer"
        else
          commit_status = "commited"
        end
        exercise_user.update!(start_at: start_at_time, end_at: Time.now, status: 1, commit_status: commit_status,
                              score: score, subjective_score: subjective_score, objective_score: objective_score,
                              commit_method: 5, reviewed: reviewed, subjective_reviewed: subjective_reviewed)
      end

      ExerciseUserScore.create!(exercise_id: @exercise.id, exercise_user_id: exercise_user.id,
                                subjective_score: subjective_score, objective_score: objective_score)
      normal_status("操作成功")
    end
  end

  #我的题库
  def my_exercises
    ActiveRecord::Base.transaction do
      ## 我的试卷题库
      @current_user_exercises = current_user.exercise_banks.find_by_c_type("Exercise")
      if @current_user_exercises.present?

        if params[:search].present?
          search_type = params[:search].to_s.strip
          @current_user_exercises = @current_user_exercises.exercise_bank_search(search_type)
        end
        page = params[:page] || 1
        limit = params[:limit] || 15
        @my_exercises_count = @current_user_exercises.size
        @current_user_exercises = @current_user_exercises.page(page).per(limit)
      else
        @current_user_exercises = []
      end
    end
  end

  # 公共题库
  def public_exercises
    ActiveRecord::Base.transaction do
      if current_user.is_certification_teacher
        @user_certification = 1 #用户已通过认证
        @public_exercises = ExerciseBank.find_by_c_type("Exercise").public_exercises
        if @public_exercises.present?
          if params[:search].present?
            search_type = params[:search].to_s.strip
            @public_exercises = @public_exercises.exercise_bank_search(search_type)
          end
          page = params[:page] || 1
          limit = params[:limit] || 15
          @public_exercises_count = @public_exercises.size
          @public_exercises = @public_exercises.page(page).per(limit)
        else
          @public_exercises_count = 0
          @public_exercises = []
        end
      else
        @user_certification = 0 #用户未通过认证
        @public_exercises_count = 0
        @public_exercises = []
      end
    end
  end

  #立即发布的弹窗内容
  def publish_modal

    ActiveRecord::Base.transaction do
      exercise_ids = params[:check_ids]
      if exercise_ids.count > 0
        @course_groups = get_user_permission_course(exercise_ids, 1)
      else
        @course_groups = []
      end
    end
  end

  # 详情页的立即发布弹框
  def publish_groups
    @current_user = current_user
    # 可立即发布的分班：当前用户管理的分班去除已发布的分班
    group_ids = @course.charge_group_ids(@current_user) - @exercise.exercise_group_settings.exercise_group_published.pluck(:course_group_id)
    @course_groups = @course.course_groups.where(id: group_ids)
    @group_settings = @exercise.exercise_group_settings.where(course_group_id: group_ids)
  end

  #首页批量或单独 立即发布,应是跳出弹窗，设置开始时间和截止时间。
  def publish
    group_ids = params[:group_ids]&.reject(&:blank?)
    if params[:detail].blank?
      tip_exception("缺少截止时间参数") if params[:end_time].blank?
      tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now)
      tip_exception("截止时间不能晚于课堂结束时间（#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}）") if @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day)
    else
      group_end_times = params[:group_end_times].reject(&:blank?).map {|time| time.to_time}
      tip_exception("缺少截止时间参数") if group_end_times.blank?
      tip_exception("截止时间和分班参数的个数不一致") if group_end_times.length != group_ids.length
      group_end_times.each do |time|
        tip_exception("分班截止时间不能早于当前时间") if time <= Time.now
        tip_exception("分班截止时间不能晚于课堂结束时间（#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}）") if @course.end_date.present? && time > @course.end_date.end_of_day
      end
    end

    ActiveRecord::Base.transaction do
      check_ids = Exercise.where(id: params[:check_ids])
      ex_end_time = params[:end_time].blank? ? Time.at(((1.month.since.to_i) / 3600.0).ceil * 3600) : params[:end_time].to_time
      check_ids.each do |exercise|
        if exercise.present?
          if exercise.unified_setting
            ex_status = exercise.exercise_status #则为试卷的状态
          else
            ex_status = @course.course_groups.where(id: params[:group_ids]).size !=
              exercise.exercise_group_settings.where(course_group_id: params[:group_ids]).exercise_group_published.size ? 1 : 0
          end
          if ex_status == 1 #如果试卷存在已发布的，或者是已截止的，那么则直接跳过
            g_course = group_ids #表示是否传入分班参数,如果传入分班的参数，那么试卷的统一设置需修改
            tiding_group_ids = g_course
            if g_course
              user_course_groups = @course.course_groups.pluck(:id) #当前课程的全部分班
              # 传入的分班和课程全部分班一致而且(传入的截止时间都一致或者是来自列表页的发布请求),则删除分班设置，统一设置设为true
              if g_course.map(&:to_i).sort == user_course_groups.sort &&
                ((params[:detail] && group_end_times.min == group_end_times.max) || params[:detail].blank?) # 如果是设置为全部班级，则试卷不用分组，且试卷设定为统一设置,否则则分组设置
                exercise.exercise_group_settings.destroy_all
                ex_unified = true
                e_time = params[:detail] ? group_end_times.max : ex_end_time
                tiding_group_ids = []
              else
                ex_unified = false
                g_course.each_with_index do |i, index|
                  exercise_group_setting = exercise.exercise_group_settings.find_in_exercise_group("course_group_id", i).first #根据课堂分班的id，寻找试卷所在的班级
                  group_end_time = params[:detail] ? group_end_times[index] : ex_end_time
                  if exercise_group_setting.present? #如果该试卷分组存在，则更新，否则新建
                    exercise_group_setting.update!(publish_time: Time.now, end_time: group_end_time)
                  else
                    p_course_group = {
                      :exercise_id => exercise.id,
                      :course_group_id => i,
                      :course_id => exercise.course.id,
                      :publish_time => Time.now,
                      :end_time => group_end_time,
                    }
                    new_exercise_group = exercise.exercise_group_settings.new p_course_group
                    new_exercise_group.save!
                  end
                end
                # group_ids = params[:group_ids]
                e_time = exercise.exercise_group_settings.end_time_no_null.map(&:end_time).max
              end
            else
              exercise.exercise_group_settings.destroy_all
              ex_unified = true
              e_time = ex_end_time
            end

            ex_status = set_exercise_status(Time.now, e_time)
            exercise_params = {
              :publish_time => Time.now,
              :end_time => e_time,
              :exercise_status => ex_status,
              :unified_setting => ex_unified
            }
            exercise.update!(exercise_params)

            if exercise.course_acts.size == 0
              exercise.course_acts << CourseActivity.new(:user_id => exercise.user_id, :course_id => exercise.course_id)
            end

            # 如果是随机组卷的话，则需要增加一步: 根据随机规则为学生分配试题
            if exercise.is_random?
              result= Benchmark.ms do
                exercise.create_exercise_questions_by_random_settings
              end
              Rails.logger.info("创建试题时长:#{result}毫秒")
            end
            ExercisePublishNotifyJob.perform_later(exercise.id, tiding_group_ids)
          end
        end
      end
      normal_status(0, "试卷发布成功！")
    end
  end

  #立即截止的弹窗内容
  def end_modal
    ActiveRecord::Base.transaction do
      exercise_ids = params[:check_ids]
      if exercise_ids.count > 0
        @course_groups = get_user_permission_course(exercise_ids, 3)
      else
        @course_groups = []
      end
    end
  end

  # 首页批量或单独 立即截止，截止时间为当前时间
  def end_exercise

    ActiveRecord::Base.transaction do
      check_ids = Exercise.where(id: params[:check_ids])
      course_students = @course.students #课堂的全部学生数
      check_ids.each do |exercise|
        exercise_status = exercise.get_exercise_status(current_user)
        if exercise_status == Exercise::PUBLISHED #跳过已截止的或未发布的
          g_course = params[:group_ids]
          if g_course.present?
            teacher_course_group_ids = @course.charge_group_ids(current_user)
            all_course_group_ids = @course.course_groups.pluck(:id)
            if exercise.unified_setting && g_course.map(&:to_i).sort == all_course_group_ids.sort #开始为统一设置
              exercise.exercise_group_settings.destroy_all
              new_ex_status = set_exercise_status(exercise.publish_time, Time.now)
              exercise.update!(:end_time => Time.now, :exercise_status => new_ex_status)
              exercise_users = exercise.exercise_users
            else
              course_members_ids = course_students.course_find_by_ids("course_group_id", g_course).pluck(:user_id).uniq #该班级的全部学生
              exercise_users = exercise.exercise_users.exercise_commit_users(course_members_ids) #参与答题的学生数
              ex_group_setting = exercise.exercise_group_settings
              old_exercise_groups = ex_group_setting.find_in_exercise_group("course_group_id", g_course) #试卷的分组设置
              left_course_groups = teacher_course_group_ids - g_course
              all_left_groups = all_course_group_ids - g_course
              left_exercise_groups = ex_group_setting.find_in_exercise_group("course_group_id", left_course_groups)
              if left_exercise_groups.blank? && exercise.unified_setting
                if all_left_groups.size > 0 #开始为统一设置，但是立即截止为分班。则创建没有立即截止的班级的exercise_group_setting
                  all_left_groups.each do |g|
                    ex_group_options = {
                      :exercise_id => exercise.id,
                      :course_group_id => g,
                      :course_id => @course.id,
                      :publish_time => exercise.publish_time,
                      :end_time => exercise.end_time
                    }
                    ExerciseGroupSetting.create!(ex_group_options)
                  end
                end
              end
              if old_exercise_groups.present?
                old_exercise_groups.update_all(:end_time => Time.now)
              else
                g_course.each do |g|
                  ex_group_options = {
                    :exercise_id => exercise.id,
                    :course_group_id => g,
                    :course_id => @course.id,
                    :publish_time => exercise.publish_time,
                    :end_time => Time.now
                  }
                  ExerciseGroupSetting.create!(ex_group_options)
                end
              end
              new_end_time = exercise.exercise_group_settings.end_time_no_null.map(&:end_time) # 试卷结束时间不为空的
              new_end_time_s = new_end_time.count > 0 ? new_end_time.max : Time.now
              new_ex_status = set_exercise_status(exercise.publish_time, new_end_time_s)
              exercise.update!(:end_time => new_end_time_s, :exercise_status => new_ex_status, :unified_setting => false)
            end
          else
            exercise_users = exercise.exercise_users
            exercise.update!(:exercise_status => 3, :end_time => Time.now, :unified_setting => true)
          end

          ex_user_ids = exercise_users.pluck(:id)

          EndExerciseCalculateJob.perform_later(ex_user_ids, exercise.id, Time.now.to_s, true, 4)
          # exercise_users.each do |user|
          #   if user.commit_status == 0 && user.start_at.present?
          #     objective_score = calculate_student_score(exercise,user.user)[:total_score]
          #     user_sub_score = user.subjective_score
          #     subjective_score = user_sub_score < 0.0 ? 0.0 : user_sub_score
          #     total_score = objective_score + subjective_score
          #     commit_option = {
          #         :status => 1,
          #         :commit_status => 1,
          #         :end_at => Time.now,
          #         :objective_score => objective_score,
          #         :score => total_score,
          #         :subjective_score => user_sub_score
          #     }
          #     user.update_attributes(commit_option)
          #   end
          # end
        end
      end
      normal_status(0, "试卷截止成功！")
    end
  end

  #学生撤销回答
  def cancel_exercise
    ActiveRecord::Base.transaction do
      ex_question_ids = @exercise.exercise_questions.pluck(:id)
      exercise_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first
      if exercise_user.present?
        if exercise_user.commited? && @exercise.get_exercise_status(current_user) == Exercise::PUBLISHED #用户已提交且试卷提交中
          if @exercise.time == -1 || ((Time.now.to_i - exercise_user.start_at.to_i) < @exercise.time.to_i * 60)
            exercise_user.update!(:score => nil, :end_at => nil, :status => nil, :commit_status => 0,
                                  :objective_score => 0.0, :subjective_score => -1.0)
            exercise_user.user.exercise_shixun_answers.search_shixun_answers("exercise_question_id", ex_question_ids).destroy_all
            exercise_answers = exercise_user.user.exercise_answers.search_answer_users("exercise_question_id", ex_question_ids)
            exercise_answers.update_all(:score => -1.0)
            all_answer_comment = ExerciseAnswerComment.search_answer_comments("exercise_question_id", ex_question_ids)
                                   .search_answer_comments("exercise_answer_id", exercise_answers.pluck(:id))
            all_answer_comment.destroy_all
            normal_status(0, "撤销回答成功")
          else
            normal_status(-1, "用户答题时间已到")
          end
        else
          normal_status(-1, "用户未提交/试卷不是提交中")
        end
      else
        normal_status(-1, "当前用户未答题")
      end
    end
  end

  #打回重做modal
  def redo_modal
    ActiveRecord::Base.transaction do
      #搜索
      if params[:realname].present?
        search_name = params[:realname]
        #搜索用户的nickname,如果存在则返回，否则继续查询用户的真实姓名或学生号
        @exercise_users = @exercise_users.includes(:user).where("LOWER(concat(users.lastname, users.firstname)) like ?",
                                                                "%#{search_name}%")
      end
      if params[:student_id].present?
        search_st_id = params[:student_id].to_i
        @exercise_users = @exercise_users.includes(user: [:user_extension])
                            .where('user_extensions.student_id like ?', "%#{search_st_id}%")
      end
      sort = params[:sort] ? params[:sort] : "asc"
      @exercise_users = @exercise_users.order("score #{sort}")
      @exercise_users_size = @exercise_users.size
      # 分页
      page = params[:page] || 1
      limit = params[:limit] || 15
      @exercise_users = @exercise_users.page(page).per(limit)
    end
  end

  #打回重做确认
  def redo_exercise
    ActiveRecord::Base.transaction do
      user_ids = params[:user_ids]
      if user_ids.present?
        redo_option = {
          :score => 0.0,
          :start_at => nil,
          :end_at => nil,
          :status => nil,
          :commit_status => 0,
          :objective_score => 0.0,
          :subjective_score => -1.0,
          :commit_method => 0,
          :reviewed => 0,
          :subjective_reviewed => 0
        }
        redo_exercise_users = @exercise_users.exercise_commit_users(user_ids)
        redo_exercise_users.update_all(redo_option)
        exercise_question_ids = @exercise.exercise_questions.pluck(:id).uniq
        ExerciseAnswer.search_answer_users("user_id", user_ids)
          .search_answer_users("exercise_question_id", exercise_question_ids).destroy_all
        ExerciseShixunAnswer.search_shixun_answers("user_id", user_ids)
          .search_shixun_answers("exercise_question_id", exercise_question_ids).destroy_all

        normal_status(0, "已成功打回重做！")
      else
        normal_status(-1, "请选择学生！")
      end
    end
  end

  #学生开始答题页面
  def start_answer
    ex_users_current = ExerciseUser.where(user_id: @exercise_current_user_id, exercise_id: @exercise.id) #不能用@exercise.exercise_users，因为exercise_users删除时，只是状态改变，未删除
    @exercise_user_current = ex_users_current&.first
    if @exercise_user_current.present?
      @exercise_user_current.update!(is_delete: 0) if @exercise_user_current.is_delete
      if @exercise_user_current.start_at.blank?
        @exercise_user_current.update!(start_at: Time.now)
      end
    else
      if @user_course_identity > Course::ASSISTANT_PROFESSOR #当为老师的时候，不创建exercise_user表，理论上老师是不能进入答题的
        exercise_user_params = {
          :user_id => @exercise_current_user_id,
          :exercise_id => @exercise.id,
          :start_at => Time.now
        }
        exercise_user_current = ExerciseUser.new(exercise_user_params)
        exercise_user_current.save!
        @exercise_user_current = exercise_user_current
      end
    end

    if @exercise_user_current.present?
      if @exercise.is_random? && @exercise_user_current.exercise_questions.count == 0
        @exercise.create_user_question_list(@exercise_user_current)
      end

      if @exercise_user_current.commit_status == 0 && @exercise.is_random? && @exercise_user_current.exercise_questions.count != @exercise_ques_count
        update_user_question_list(@exercise_user_current, @exercise)
      end
    end

    @t_user_exercise_status = @exercise.get_exercise_status(current_user)

    @user_left_time = nil
    if @user_course_identity < Course::STUDENT || (@t_user_exercise_status == Exercise::DEADLINE) ||
      (ex_users_current.exists? && (@exercise_user_current.commited? || @exercise_user_current.commit_with_no_answer?))
      @user_exercise_status = 1 #当前用户为老师/试卷已截止/试卷已提交不可编辑
    else
      @user_left_time = get_exercise_left_time(@exercise, current_user)
      @user_exercise_status = 0 #可编辑
    end

    @exercise_questions = @exercise.is_random? ? @exercise_user_current.exercise_questions : @exercise.exercise_questions

    if !@exercise.is_random? && @exercise.question_random
      @exercise_questions = @exercise_questions.order("RAND()")
    else
      @exercise_questions = @exercise_questions.order("question_number ASC")
    end
    # 判断问题是否已回答还是未回答
    @exercise_questions = @exercise_questions.includes(:exercise_shixun_challenges,
                                                       :exercise_shixun_answers,
                                                       :exercise_answers,
                                                       :exercise_standard_answers)

    if @t_user_exercise_status == Exercise::DEADLINE
      get_each_student_exercise(@exercise.id, @exercise_questions, @exercise_current_user_id)
    end
    get_user_answer_status(@exercise_questions, @exercise_current_user_id, @exercise, @t_user_exercise_status)

  end

  #提交试卷前的弹窗
  def begin_commit
    ActiveRecord::Base.transaction do
      if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时
        exercise_user = @exercise.exercise_users.find_by(user_id: current_user.id)
        if @exercise.is_random?
          @exercise_questions = exercise_user.exercise_questions
        else
          @exercise_questions = @exercise.exercise_questions
        end
        @shixun_undo = 0
        @ques_undo = 0
        @oj_undo = 0
        ex_answer_time = @exercise.time.to_i
        if ex_answer_time > 0 #有剩余时间的时候
          user_left_time = get_exercise_left_time(@exercise, current_user)
          @ex_end_time = Time.now + user_left_time.to_i.seconds

          # 提交用户试卷
          commit_exercise_user @exercise, exercise_user if user_left_time.nil?
        else
          @ex_end_time = @exercise.get_exercise_end_time(current_user.id)

          commit_exercise_user @exercise, exercise_user if @ex_end_time.present? && @ex_end_time < Time.now
        end
        # @ex_end_time = @exercise.get_exercise_end_time(current_user.id)
        # if ex_answer_time > 0
        #   left_answer_time = Time.now + ex_answer_time.minutes  #判断试卷的倒计时和截止时间哪个先到
        #   if left_answer_time < @ex_end_time
        #     exercise_end_time = @exercise.exercise_users.exercise_commit_users(current_user.id)
        #     if exercise_end_time.present?
        #       ex_end_times =  exercise_end_time.first.start_at.nil? ? Time.now : exercise_end_time.first.start_at
        #       @ex_end_time = ex_end_times + ex_answer_time.minutes
        #     end
        #   end
        # end
        @exercise_questions.each do |q|
          if q.question_type == Exercise::PRACTICAL #当为实训题时
            user_myshixun = q.shixun.myshixuns.search_myshixun_user(current_user.id)
            if user_myshixun.blank? || user_myshixun.first.created_at < exercise_user.start_at || user_myshixun.first.status != Exercise::UNPUBLISHED #当前用户的实训是否做完
              @shixun_undo += 1
              @oj_undo += 1
              @ques_undo += 1
            end
          elsif q.question_type == Exercise::PROGRAM #当为编程题时
            user_hack = q.hack_user(current_user.id)
            if user_hack.blank? || !user_hack.passed?
              @oj_undo += 1
              @ques_undo += 1
            end
          else
            ques_vote = q.exercise_answers.search_exercise_answer("user_id", current_user.id)
            if ques_vote.blank?
              @ques_undo += 1
            end
          end
        end
      end
    end
  end

  # 学生提交试卷
  def commit_exercise
    tip_exception(0, "试卷截止时间已到，系统已自动提交") if (@answer_committed_user.commited? || @answer_committed_user.commit_with_no_answer?)
    ActiveRecord::Base.transaction do
      can_commit_exercise = false
      user_left_time = nil
      if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时
        if params[:commit_method].to_i == 2 #自动提交时
          user_left_time = get_exercise_left_time(@exercise, current_user)
          Rails.logger.info("######__________auto_commit_user_left_time_________################{user_left_time}")
          if user_left_time.to_i <= 0
            can_commit_exercise = true
          end
        else
          can_commit_exercise = true
        end
        if can_commit_exercise
          commit_exercise_user @exercise, @answer_committed_user, Time.now
          CommitExercsieNotifyJobJob.perform_later(@exercise.id, current_user.id)
          normal_status(0, "试卷提交成功！")
        else
          normal_status(-2, "#{user_left_time.to_i}")
        end
      else
        normal_status(-1, "提交失败，当前用户不为课堂学生!")
      end
    end
  end

  # 返回返回指定试卷下指定学生的信息
  def get_next_exercise_user
    # 默认是按照答题列表中的顺序获取学生已提交且教师未评阅并且是教师所管理的班级的第一条记录
    @exercise_users = @exercise.all_exercise_users(current_user.id).
        exercise_user_committed.
        exercise_unreview.
        order("end_at desc")
    @exercise_user = @exercise_users.first
    if params[:student_login].present?
      @ex_user = @exercise.all_exercise_users(current_user.id).joins(:user).where(users: {login: params[:student_login]}).first
      # 如果该学生作品已评阅
      if @ex_user.reviewed
        @exercise_users.where("end_at < :end_at", end_at: @ex_user.end_at).first
      else
        # 如果该学生作品未评阅
        index = @exercise_users.map(&:user).map(&:login).index(params[:student_login]).to_i
        @exercise_user = @exercise_users[index+1]
      end
    end
  end

  #教师评阅试卷 及学生查看试卷
  def review_exercise
    ActiveRecord::Base.transaction do
      # 1 老师权限，0 学生权限
      @is_teacher_or = (@user_course_identity < Course::STUDENT) ? 1 : 0
      @student_status = 2

      if @exercise.is_random?
        @exercise_questions = @ex_user.exercise_questions.
            includes(
                :exercise_shixun_challenges, :exercise_standard_answers,
                :exercise_answers, :exercise_shixun_answers,
                :exercise_answer_comments
            ).order("question_number ASC")
      else
        @exercise_questions = @exercise.exercise_questions.
            includes(
                :exercise_shixun_challenges, :exercise_standard_answers,
                :exercise_answers, :exercise_shixun_answers,
                :exercise_answer_comments
            ).order("question_number ASC")
      end
      @question_status = []
      get_exercise_status = @exercise.get_exercise_status(current_user) #当前用户的试卷状态
      @ex_answer_status = @exercise.get_exercise_status(@ex_user&.user) #当前试卷用户的试卷状态
      if @ex_user.present? && @is_teacher_or == 0
        if get_exercise_status == Exercise::PUBLISHED #当前用户已提交，且试卷未截止
          if @ex_user.none_commit? #学生未提交，且当前为学生
            @student_status = 0
          else
            @student_status = 1 #学生已提交，且当前是学生
            get_user_answer_status(@exercise_questions, @exercise_current_user_id, @exercise, get_exercise_status)
          end
        end
      end
      # 如果当前答题用户为教师
      if @student_status == 2
        get_each_student_exercise(@exercise.id, @exercise_questions, @exercise_current_user_id)
      end
      @exercise_user_current = @ex_user
    end
  end

  # 批量评阅时,展示所有已选学生(由前端通过user_ids传递过来)的姓名、客观题分数，标记已评与未评的题目(该批次学生全部已评阅，则该题为已评，如果至少有一人该题未评，则为未评阅)
  def review_exercises_by_students
    tip_exception(-1, "user_ids为空或不为数组") if params[:user_ids].blank? || !params[:user_ids].is_a?(Array)
    @exercise_users = @exercise.exercise_users.where(user_id: params[:user_ids])
    tip_exception(-1, "批量评阅仅支持对评阅中、未评阅的学生进行") if @exercise_users.exists?(reviewed: true)
    tip_exception(-1, "不支持对未交卷/考试中的学生进行评阅") if @exercise_users.exists?(commit_status: "none_commmit")
    if @exercise_users.blank?
      # 该试卷下所有答题用户
      @exercise_users = @exercise.exercise_users.
          where(user_id: params[:user_ids]).
          includes(:user).joins(:user).order("users.lastname desc")
    else
      @exercise_users = @exercise_users.includes(:user).joins(:user).order("users.lastname desc")
    end
    # 该试卷下所有试题
    @exercise_questions = @exercise.exercise_questions.subjectives.
        includes(:exercise_answers, :exercise_shixun_answers)
    # 该试卷下所有试题是否全部已评状态
    @all_exercise_question_reviewed_status = {}
    # 该试卷下所有试题是否部分已评状态
    @all_exercise_question_partial_reviewed_status = {}
    @exercise_questions.collect do |exercise_question|
      # 只判断主观题是否评阅
      # 需要判断当前给过来的全部用户是否已评阅
      #
      # 当前页面用户数与问题的回答数相等
      exercise_answers_by_users = exercise_question.exercise_answers.by_user(@exercise_users.pluck(:user_id))
      if exercise_answers_by_users.size == @exercise_users.size
        # 而且，所有回答都已评，就算作已评阅
        if exercise_answers_by_users.all?{|answer| answer.score >= 0}
          @all_exercise_question_reviewed_status[exercise_question.id] = true
        else
          @all_exercise_question_reviewed_status[exercise_question.id] = false
        end
      else
        @all_exercise_question_reviewed_status[exercise_question.id] = false
      end
      # 当前试题是否部分已评,只要存在exercise_answers而且分数>=0，就算已评
      if exercise_answers_by_users.any?{|exercise_answer| exercise_answer.present? && exercise_answer.score >= 0}
        @all_exercise_question_partial_reviewed_status[exercise_question.id] = true
      else
        @all_exercise_question_partial_reviewed_status[exercise_question.id] = false
      end
    end
  end

  #答题列表
  def exercise_lists
    # @exercise_users = @exercise_users
    @exercise_users = @exercise_users.
        includes(:exercise=>[:course=>[:course_members, :course_groups]], :user=>[:user_extension]) if @exercise_users.present?
    # 将该课堂下,每个学生所属分班 按user_id分组取出
    @student_course_groups_hash = @exercise.course.students.
        left_joins(:course_group).select(
          "course_members.user_id user_id",
          "course_members.course_group_id course_group_id",
          "course_groups.name course_group_name"
        ).group_by{|stu| stu.user_id}
    # 该课堂下所有已激活且角色为STUDENT(也就是 学生)的user_id取出
    @user_ids_in_course = @exercise.course.students.where(is_active: 1).pluck(:user_id)
    @current_user_id = current_user.id
    exercise_ids = [@exercise.id]
    # 获取试卷对于当前用户的状态
    @exercise_status = @exercise.get_exercise_status(current_user)
    # 课堂所有学生
    @course_all_members = @course.students
    # 该课堂所有分班
    @c_group_counts = @course.course_groups_count
    # 该试卷下所有试题类型
    question_types = @exercise.exercise_questions.pluck(:question_type).uniq

    @exercise_publish_count = get_user_permission_course(exercise_ids, Exercise::PUBLISHED).count #判断是否有已发布的分班
    @exercise_unpublish_count = get_user_permission_course(exercise_ids, Exercise::UNPUBLISHED).count #判断是否有未发布的分班

    if (question_types.size >= 1) && question_types.include?(Exercise::SUBJECTIVE) #是否包含主观题,或者是否大于1
      @subjective_type = 1
    else
      @subjective_type = 0
    end
    if (question_types.size >= 1) && (question_types & ([Exercise::SINGLE, Exercise::MULTIPLE, Exercise::JUDGMENT, Exercise::COMPLETION, Exercise::PRACTICAL, Exercise::PROGRAM])).present? #是否包含客观题,或者是否大于1
      @objective_type = 1
    else
      @objective_type = 0
    end

    if @exercise_unanswers < 0
      @exercise_unanswers = 0
    end


    if params[:format] == "xlsx"
      if @user_course_identity > Course::ASSISTANT_PROFESSOR
        tip_exception(403, "无权限操作")
      elsif @exercise_status == Exercise::UNPUBLISHED
        normal_status(-1, "试卷未发布")
      elsif (@exercise_users_size == 0) || (@export_ex_users&.exercise_user_committed.size == 0)
        normal_status(-1, "暂无用户提交")
      elsif params[:export].present? && params[:export]
        normal_status(0, "正在下载中")
      else
        respond_to do |format|
          format.xlsx {
            set_export_cookies
            get_export_users(@exercise, @course, @export_ex_users)
            exercise_export_name_ =
              "#{current_user.real_name}_#{@course.name}_#{@exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
            render xlsx: "#{exercise_export_name_.strip}", template: "exercises/exercise_lists.xlsx.axlsx", locals: {table_columns: @table_columns, exercise_users: @user_columns}
          }
        end
      end
    end
  end

  #导出空白试卷
  def export_exercise
    tip_exception("随机试卷无法导出") if @exercise.is_random?
    @request_url = request.base_url
    @exercise_questions = @exercise.exercise_questions.includes(:exercise_choices).order("question_number ASC")
    filename_ = "#{@exercise.user.real_name}_#{@course.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
    stylesheets = "#{Rails.root}/app/templates/exercise_export/exercise_export.css"
    if params[:export].present? && params[:export]
      normal_status(0, "正在下载中")
    else
      set_export_cookies
      render exam_pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets, disposition: 'inline', type: "pdf_attachment.content_type", stream: false
    end
  end

  #空白试卷预览页面,仅供测试使用，无其他任何用途
  def blank_exercise
    ActiveRecord::Base.transaction do
      begin
        @exercise_questions = @exercise.exercise_questions.order("question_number ASC")
        challenge_ids = @exercise_questions.joins(:exercise_shixun_challenges).pluck("exercise_shixun_challenges.challenge_id")
        # get_each_student_exercise(@exercise.id,@exercise_questions,31798)
        # @games = @exercise_user.user.games.ch_games(challenge_ids)
        respond_to do |format|
          format.html
        end
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception("没有权限")
        raise ActiveRecord::Rollback
      end
    end
  end

  #学生的统计结果
  def exercise_result
    exercise_ids = [@exercise.id]
    @exercise_publish_count = get_user_permission_course(exercise_ids, Exercise::PUBLISHED).size #判断是否有已发布的分班
    @exercise_unpublish_count = get_user_permission_course(exercise_ids, Exercise::UNPUBLISHED).size #判断是否有未发布的分班
    @course_all_members = @course.students #课堂的全部学生
    @exercise_all_users = @exercise.exercise_users
    ex_common_ids = @exercise.common_published_ids(current_user.id)
    @exercise_course_groups = @course.get_ex_published_course(ex_common_ids)

    #班级的选择
    if params[:exercise_group_id].present?
      group_id = params[:exercise_group_id]
      exercise_students = @course_all_members.course_find_by_ids("course_group_id", group_id) # 试卷所分班的全部人数
      user_ids = exercise_students.pluck(:user_id).reject(&:blank?)
      @exercise_all_users = @exercise.exercise_users.exercise_commit_users(user_ids)
      @course_all_members_count = @exercise_all_users.size
    else
      @exercise_users_list = @exercise.all_exercise_users(current_user.id)
      @course_all_members_count = @exercise_users_list.size
    end
    @exercise_commit_users = @exercise_all_users.where(commit_status: [1]) #试卷的已交卷用户
    @exercise_commit_user_ids = @exercise_commit_users.pluck(:user_id).uniq #已提交试卷的全部用户id
    @exercise_commit_user_counts = @exercise_commit_users.size #试卷的已提交用户人数
    @exercise_status = @exercise.get_exercise_status(current_user)

    #提交率
    if @course_all_members_count == 0
      commit_percent = 0.00
      min_score = 0.0
      max_score = 0.0
      average_score = 0.0
      fail_counts = 0
      pass_counts = 0
      good_counts = 0
      best_counts = 0
    else
      commit_percent = (@exercise_commit_user_counts / @course_all_members_count.to_f).round(3) # 已提交人数
      exercise_scores = @exercise_commit_users.pluck(:score).reject(&:blank?) # 已提交的学生分数集合
      min_score = exercise_scores.min.present? ? exercise_scores.min : 0.0 # 已提交学生中的最小分
      max_score = exercise_scores.max.present? ? exercise_scores.max : 0.0 # 已提交学生中的最高分
      total_score = exercise_scores.sum.present? ? exercise_scores.sum : 0.0 # # 已提交的所有学生分数之和
      average_score = @exercise_commit_user_counts > 0 ? (total_score.round(1) / @exercise_commit_user_counts).round(1) : 0.0 # 平均分
      question_scores = @exercise.question_scores # 试卷总分
      fail_score = question_scores * 0.6.round(2) # 及格分
      pass_score = question_scores * 0.7.round(2) # 良好分
      good_score = question_scores * 0.9.round(2) # 优秀分

      fail_counts = exercise_scores.count {|a| a < fail_score} # 不及格人数
      pass_counts = exercise_scores.count {|a| a < pass_score && a >= fail_score} # 及格人数
      good_counts = exercise_scores.count {|a| a < good_score && a >= pass_score} # 良好人数
      best_counts = exercise_scores.count {|a| a >= good_score && a <= question_scores} # 优秀人数
    end
    @counts_array = {
      :commit_percent => commit_percent,
      :min_score => min_score.to_s,
      :max_score => max_score.to_s,
      :average_score => average_score.to_s,
      :fail_counts => fail_counts,
      :pass_counts => pass_counts,
      :good_counts => good_counts,
      :best_counts => best_counts,
    }

    @exercise_questions = @exercise.exercise_questions&.includes(:exercise_choices, :exercise_answers, :exercise_standard_answers, :exercise_shixun_challenges, :exercise_shixun_answers)
    @exercise_questions_count = @exercise_questions.size

    percent_sort = "desc"

    if params[:sort].present?
      percent_sort = params[:sort]
    end
    # @paging_type = "percent"
    # # 按题型排序
    # if params[:sort].present?
    #   @paging_type = params[:sort].to_s
    # end


    if @exercise.is_random?
      ques_result_all = random_exercise_commit_result(@exercise, @exercise_commit_users)
      Rails.logger.info "=============================统计结果获取完成exercise_id: #{@exercise.id} exercise_user_ids:#{@exercise_commit_users.map(&:id)}============================="
      Rails.logger.info(ques_result_all)
      @question_result_hash = ques_result_all.sort_by {|s| s[:question_type]}
    else
      ques_result_all = exercise_commit_result(@exercise_questions, @exercise_commit_user_ids)

      #默认降序排列
      if percent_sort == "desc"
        @question_result_hash = ques_result_all.sort_by {|s| s[:percent]}.reverse
      else
        @question_result_hash = ques_result_all.sort_by {|s| s[:percent]}
      end

      @page = params[:page] || 1
      @limit = params[:limit] || 10
      @question_result_hash = Kaminari.paginate_array(@question_result_hash).page(@page).per(@limit)
    end
  end

  # 返回一个学生的试卷的各类客观题得分
  def get_objective_scores
    @exercise_user = @exercise.exercise_users.find_by(user_id: params[:user_id])

    @exercise_answers = @exercise.exercise_answers.where(user_id: params[:user_id])

    @single_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::SINGLE}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::SINGLE)
    @multiple_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::MULTIPLE}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::MULTIPLE)
    @judgement_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::JUDGMENT}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::JUDGMENT)
    @completion_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::COMPLETION}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::COMPLETION)
    @shixun_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::PRACTICAL}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::PRACTICAL)
    @program_question_score = @exercise_answers.joins(:exercise_question).where(exercise_questions: {question_type: Exercise::PROGRAM}).
        where("score >= 0").pluck(:score).reject(&:blank?).sum if @exercise.exercise_questions.exists?(question_type: Exercise::PROGRAM)
  end

  private

  def exercise_params
    params.require(:exercise).permit(:exercise_name, :exercise_description, :course_id, :exercise_status, :user_id, :time,
                                     :publish_time, :end_time, :show_result, :question_random, :choice_random, :is_public,
                                     :score_open, :answer_open, :exercise_bank_id, :unified_setting, :show_statistic)
  end

  def is_course_teacher
    unless @user_course_identity < Course::STUDENT #为老师/助教/管理员
      normal_status(403, "...")
    end
  end

  #检查传入的参数内容是否符合
  def validates_exercise_params
    normal_status(-1, "试卷标题不能为空！") if params[:exercise_name].blank?
    normal_status(-1, "试卷标题不能超过60个字符") if (params[:exercise_name].length > 60)
    normal_status(-1, "试卷须知不能超过100个字符") if (params[:exercise_description].present? &&
      params[:exercise_description].length > 100)
  end

  #判断设置的时间是否合理
  def validate_publish_time
    # 截止时间存在，且截止时间必须大于当前时间或发布时间
    unified_setting = params[:unified_setting]
    publish_course = params[:publish_time_groups]
    if @course.is_end
      normal_status(-1, "课堂已结束不能再修改")
    elsif unified_setting
      ex_group_settings = @exercise.exercise_group_settings
      if ex_group_settings.present?
        p_time_present = ex_group_settings.publish_time_no_null.map(&:publish_time).min
        if p_time_present && p_time_present < Time.now
          normal_status(-1, "设置失败，存在已发布的分班")
        end
      elsif params[:publish_time].blank?
        normal_status(-1, "发布时间不允许为空")
      end
    elsif unified_setting.present? && !unified_setting #非统一设置，分班不能为空
      if publish_course.present?
        course_ids = publish_course.map {|a| a[:course_group_id]}.sum
        publish_t = publish_course.map {|a| a[:publish_time]}
        if course_ids.include?(nil) || course_ids.count == 0
          normal_status(-1, "请选择分班")
        elsif publish_t.include?(nil) || publish_t.count == 0
          normal_status(-1, "发布时间不允许为空")
        end
      else
        normal_status(-1, "请选择分班")
      end
    end
  end

  def get_exercise
    @exercise = Exercise.find_by(id: params[:id])
    if @exercise.blank?
      normal_status(404, "试卷不存在")
    else
      @course = @exercise.course
      normal_status(404, "课堂不存在") if @course.blank?
    end
  end

  def get_exercise_question_counts #获取试卷的问题数及总分数
    if @exercise.is_random?
      @exercise_random_settings = @exercise.exercise_random_settings
      @exercise_score_settings = @exercise.exercise_score_settings

      @exercise_single_ques_count = @exercise_random_settings.SINGLE.pluck(:quanlity).sum
      @exercise_single_ques_scores = @exercise_score_settings.SINGLE.pluck(:score).sum.round(1) * @exercise_single_ques_count

      @exercise_double_ques_count = @exercise_random_settings.MULTIPLE.pluck(:quanlity).sum
      @exercise_double_ques_scores = @exercise_score_settings.MULTIPLE.pluck(:score).sum.round(1) * @exercise_double_ques_count

      @exercise_ques_judge_count = @exercise_random_settings.JUDGMENT.pluck(:quanlity).sum
      @exercise_ques_judge_scores = @exercise_score_settings.JUDGMENT.pluck(:score).sum.round(1) * @exercise_ques_judge_count

      @exercise_ques_null_count = @exercise_random_settings.COMPLETION.pluck(:quanlity).sum
      @exercise_ques_null_scores = @exercise_score_settings.COMPLETION.pluck(:score).sum.round(1) * @exercise_ques_null_count

      @exercise_ques_main_count = @exercise_random_settings.SUBJECTIVE.pluck(:quanlity).sum
      @exercise_ques_main_scores = @exercise_score_settings.SUBJECTIVE.pluck(:score).sum.round(1) * @exercise_ques_main_count

      @exercise_ques_shixun_count = @exercise_random_settings.PRACTICAL.pluck(:quanlity).sum
      @exercise_ques_shixun_scores = @exercise_score_settings.PRACTICAL.pluck(:score).sum.round(1) * @exercise_ques_shixun_count

      @exercise_ques_pro_count = @exercise_random_settings.PROGRAM.pluck(:quanlity).sum
      @exercise_ques_pro_scores = @exercise_score_settings.PROGRAM.pluck(:score).sum.round(1) * @exercise_ques_pro_count

      @exercise_ques_count = @exercise_random_settings.pluck(:quanlity).sum
      @exercise_ques_scores = @exercise_ques_pro_scores + @exercise_ques_shixun_scores + @exercise_ques_main_scores + @exercise_ques_null_scores + @exercise_ques_judge_scores + @exercise_double_ques_scores + @exercise_single_ques_scores
    else
      exercise_questions = @exercise.exercise_questions
      @exercise_ques_count = exercise_questions.size # 全部的题目数
      @exercise_ques_scores = exercise_questions.pluck(:question_score).map(&:to_f).sum.round(1)

      #单选题的数量及分数
      exercise_single_ques = exercise_questions.find_by_custom("question_type", Exercise::SINGLE)
      @exercise_single_ques_count = exercise_single_ques.size
      @exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).map(&:to_f).sum.round(1)

      #多选题的数量及分数
      exercise_double_ques = exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE)
      @exercise_double_ques_count = exercise_double_ques.size
      @exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).map(&:to_f).sum.round(1)

      # 判断题数量及分数
      exercise_ques_judge = exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT)
      @exercise_ques_judge_count = exercise_ques_judge.size
      @exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).map(&:to_f).sum.round(1)

      #填空题数量及分数
      exercise_ques_null = exercise_questions.find_by_custom("question_type", Exercise::COMPLETION)
      @exercise_ques_null_count = exercise_ques_null.size
      @exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).map(&:to_f).sum.round(1)

      #简答题数量及分数
      exercise_ques_main = exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE)
      @exercise_ques_main_count = exercise_ques_main.size
      @exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).map(&:to_f).sum.round(1)

      #实训题数量及分数
      exercise_ques_shixun = exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL)
      @exercise_ques_shixun_count = exercise_ques_shixun.size
      @exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).map(&:to_f).sum.round(1)

      #编程题数量及分数
      exercise_ques_pro = exercise_questions.find_by_custom("question_type", Exercise::PROGRAM)
      @exercise_ques_pro_count = exercise_ques_pro.size
      @exercise_ques_pro_scores = exercise_ques_pro.pluck(:question_score).map(&:to_f).sum.round(1)

      @exercise_questions = @exercise_questions&.includes(:exercise_choices, :exercise_shixun_challenges, :exercise_answers, :exercise_shixun_answers, :exercise_answer_comments, :exercise_standard_answers)
    end
  end

  #获取用户有权限的分班
  def get_user_permission_course(exercise_ids, status)
    exercise_status = status.to_i #传入的试卷发布状态
    unpublish_group = []
    course_groups = []
    user_groups_id = @course.charge_group_ids(current_user)
    exercises_all = Exercise.includes(:exercise_group_settings).where(id: exercise_ids)
    exercises_all.each do |exercise|
      if exercise.present?
        if exercise.unified_setting #统一设置只有两种情况，全部发布，全部截止
          exercise_user_status = exercise.get_exercise_status(current_user) #当前用户的能看到的试卷
          if (exercise_user_status == exercise_status) || exercise_status == Exercise::DEADLINE #未发布的情况
            unpublish_group = unpublish_group + user_groups_id
          end
        else
          ex_all_group_settings = exercise.exercise_group_settings
          ex_group_settings = ex_all_group_settings.exercise_group_published.pluck(:course_group_id).uniq #问卷设置的班级
          if exercise_status == Exercise::UNPUBLISHED
            unpublish_group = user_groups_id - ex_group_settings
          elsif exercise_status == Exercise::DEADLINE
            ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq
            ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班
            unpublish_group = unpublish_group + ex_and_user - ex_ended_groups #已发布的全部班级减去截止的全部班级
          else
            ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq
            ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班
            unpublish_group = unpublish_group + ex_and_user - ex_ended_groups
          end
        end
      end
    end
    Rails.logger.info("#####____________unpublish_group_______#######{unpublish_group}")
    unpublish_group = unpublish_group.uniq
    if unpublish_group.count > 0
      course_groups = CourseGroup.by_group_ids(unpublish_group)
    end
    course_groups
  end

  def set_exercise_status(publish_time, end_time)
    time_now_i = Time.now
    if publish_time.present? && (publish_time <= time_now_i) && (end_time > time_now_i)
      2
    elsif publish_time.nil? || (publish_time.present? && publish_time > time_now_i)
      1
    elsif end_time.present? && (end_time <= time_now_i)
      3
    elsif end_time.present? && publish_time.present? && (end_time < publish_time)
      normal_status(-1, "时间设置错误！")
    else
      1
    end
  end

  def check_course_public
    unless @course.is_public == 1 # 0为私有，1为公开
      normal_status(403, "...")
    end
  end

  def check_user_id_start_answer #判断用户在开始答题时，是否有用户id传入,如果为老师，则id必需，否则为当前用户的id
    user_login = params[:login]
    if user_login.blank? && @user_course_identity < Course::STUDENT #id不存在，且当前为老师/管理员等
      normal_status(-1, "请输入学生登陆名！")
    else
      if @user_course_identity < Course::STUDENT || @exercise.score_open
        @ex_answerer = user_login.blank? ? current_user : User.find_by(login: user_login)
      else
        @ex_answerer = current_user
      end

      if @ex_answerer.blank?
        normal_status(404, "答题用户不存在")
      elsif @user_course_identity > Course::STUDENT && !@exercise.is_public
        normal_status(403, "非公开试卷")
      else
        # @exercise_current_user_id = @ex_answerer.id || current_user.id
        @exercise_current_user_id = @ex_answerer.id
      end
    end
  end

  ## 判断开始答题页面的用户权限
  def check_user_on_answer
    if @user_course_identity == Course::STUDENT && @exercise.get_exercise_status(current_user) == Exercise::UNPUBLISHED #试卷未发布，且当前用户不为老师/管理员
      normal_status(-1, "未发布试卷！")
    elsif @user_course_identity > Course::STUDENT && (!@exercise.is_public || (@exercise.is_public && !@exercise.unified_setting)) ##不为课堂成员，且试卷不为公开的,或试卷公开，但不是统一设置的
      normal_status(-1, "试卷暂未公开！")
    end
  end

  def check_exercise_time
    @answer_committed_user = @exercise.exercise_users.exercise_commit_users(current_user.id)&.first
    if @answer_committed_user.blank?
      normal_status(404, "答题用户不存在")
    end
  end

  #打回重做时的初步判断
  def check_exercise_status
    #当前教师所在分班的全部已提交的学生数
    @exercise_users = @exercise.all_exercise_users(current_user.id).
        commit_exercise_by_status([ExerciseUser.commit_statuses[:commited], ExerciseUser.commit_statuses[:commit_with_no_answer]])
    if @exercise.get_exercise_status(current_user) != Exercise::PUBLISHED
      normal_status(-1, "非提交中的试卷不允许打回重做！")
    elsif @exercise_users.count < 1
      normal_status(-1, "暂无人提交试卷！")
    end
  end


  #查看试题页面，当为学生时，除非试卷已截止，或已提交才可以查看
  def check_exercise_is_end
    ex_status = @exercise.get_exercise_status(current_user)
    @ex_user = @exercise.exercise_users.find_by(user_id: @exercise_current_user_id) #该试卷的回答者
    if @user_course_identity > Course::ASSISTANT_PROFESSOR
      if ex_status == Exercise::UNPUBLISHED
        normal_status(-1, "试卷未发布")
      elsif @ex_user.present? && @ex_user.none_commit?
        normal_status(-1, "试卷未提交")
      elsif params[:user_id].present? && current_user.id != params[:user_id]
        normal_status(-1, "不能查看他人的试卷")
      end
    end
  end

  #查看试卷是否选择为公开统计
  def check_exercise_public
    if @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生,试卷公开统计，且已截止，且已提交
      ex_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first
      unless @exercise.get_exercise_status(current_user) == Exercise::DEADLINE && ex_user.present? && ex_user.commited? &&
        @exercise.show_statistic
        normal_status(-1, "学生暂不能查看")
      end
    end
  end

  def get_left_banner_id
    left_banner_content = @course.course_modules.search_by_module_type("exercise")
    if left_banner_content.present?
      @left_banner_id = left_banner_content.first.id
      @left_banner_name = left_banner_content.first.module_name
    else
      normal_status(404, "左侧导航不存在")
    end
  end

  def get_user_answer_status(exercise_questions, user_id, exercise, exercise_user_status)
    @question_status = []
    @exercise_all_questions = []
    ex_question_random = exercise.question_random
    question_answered = 0
    exercise_questions.each_with_index do |q, index|
      if ex_question_random && exercise_user_status != Exercise::DEADLINE
        ques_number = index + 1
      else
        ques_number = q.question_number
      end
      ques_status = 0
      if q.question_type < Exercise::PRACTICAL
        ques_vote = q.exercise_answers.select {|answer| answer.user_id == user_id}

        if ques_vote.present?
          #其他题目，需回答的有内容，才会为已答，否则如内容为空，视为未答
          vote_answer_id = ques_vote.pluck(:exercise_choice_id).reject(&:blank?)
          vote_text_count = ques_vote.pluck(:answer_text).reject(&:blank?).size
          if q.question_type <= Exercise::JUDGMENT #选择题和判断题的时候，需要有选项，才算回答
            if vote_answer_id.size > 0
              ques_status = 1
              question_answered += 1
            end
          else
            if vote_text_count > 0 #主观题，必选有内容，才算回答
              ques_status = 1
              question_answered += 1
            end
          end
        end
      elsif q.question_type == Exercise::PRACTICAL
        if Myshixun.exists?(user_id: user_id, shixun_id: q.shixun_id)
          ques_status = 1
          question_answered += 1
        end
      elsif q.question_type == Exercise::PROGRAM
        if q.hack_user(user_id).present?
          ques_status = 1
          question_answered += 1
        end
      end
      question_status = {
        :ques_id => q.id,
        :ques_number => ques_number, #仅问题的显示位置变化，但是问题的question_number 不会变化，与之相关的choice/standard_answer/answer不会变化
        :ques_status => ques_status,
      }
      question_options = {
        :question => q,
        :ques_number => ques_number,
      }
      @question_status = @question_status.push(question_status).sort_by {|k| k[:ques_number]}
      @exercise_all_questions = @exercise_all_questions.push(question_options).sort_by {|k| k[:ques_number]}
    end
  end

  #下一步也有check_on_users再进行判断
  def only_student_in
    if @user_course_identity < Course::STUDENT
      normal_status(-1, "老师身份不允许进入")
    end
  end

  #判断实训是否已选择
  def commit_shixun_present
    question_shixun_ids = @exercise.exercise_questions.pluck(:shixun_id).reject(&:blank?)
    shixun_id = params[:shixun_id]
    @shixun = Shixun.find_by(id: shixun_id)
    if shixun_id.present? && question_shixun_ids.include?(shixun_id)
      normal_status(-1, "该实训已选择！")
    elsif @shixun.blank?
      normal_status(-1, "该实训不存在！")
    end
  end

  # 答题列表的提交状态过滤
  def commit_status_filter exercise_users_list, type
    # 3为已交卷未答 2为已交卷 1为进行中，0为未开始
    result = case type
              when 0
                exercise_users_list.where("start_at is null")
              when 1
                exercise_users_list.where("start_at is not null and commit_status = 0")
              when 2
                exercise_users_list.commited
              when 3
                exercise_users_list.commit_with_no_answer
             end
    return result
  end

  def update_reviewed_status
    # 老师查看时更新评阅状态状态
    if @is_teacher_or == 1 && @ex_user.present? && @ex_user.commited? && (@exercise.subject_question_ids.blank? || @ex_user.subjective_reviewed)
      # 如果所有主观题都已评阅的话更新评阅状态为已评阅
      all_subjective_exercise_answers =  @exercise.subjective_exercise_answers.where(user_id: @ex_user.user_id)
      if (all_subjective_exercise_answers.size == @exercise.subjective_exercise_questions.size)
        if (all_subjective_exercise_answers.all?{|ex| ex.score>=0})
          @ex_user.update!(reviewed: 1)
        end
      end
    end
  end

  # 答题列表页以及批量评阅时获取exercise_users
  def get_exercise_users_list
    Rails.logger.info("==============================获取exercise_users==============================")
    @exercise_status = @exercise.get_exercise_status(current_user)
    # 课堂所有学生
    @course_all_members = @course.students
    # 该课堂所有分班
    @c_group_counts = @course.course_groups_count

    #初始化值
    @exercise_users = [] #答题用户列表
    @exercise_course_groups = [] #当前用户有权限的班级
    @exercise_unanswers = 0 # 未开始用户数
    @exercise_answers = 0 #已交卷用户数
    @exercise_answerings = 0 #进行中用户数
    @exercise_users_count = 0 #全部用户数
    @teacher_review_count = 0 #已评数
    @teacher_unreview_count = 0 #未评数

    #试卷的答题列表页的显示用户
    if @user_course_identity < Course::STUDENT #当前为老师，而且老师只能查看自己班级的/课堂的试卷
      @exercise_current_user_status = 0
      # 如果试卷状态为未发布，则不进一步筛选，否则(已发布、已截止、已结束)
      if @exercise_status != Exercise::UNPUBLISHED
        ex_common_ids = @exercise.common_published_ids(current_user.id) #当前用户在该试卷下发布的分班的id数组
        # 根据班级id数组,整理成对应的各个班的名称和班级人数
        # [
        #   {
        #     course_name: "班级1",
        #     course_id: 1,
        #     student_count: 10
        #   },
        #   {
        #     course_name: "班级2",
        #     course_id: 2,
        #     student_count: 20
        #   },
        # ]
        @exercise_course_groups = @course.get_ex_published_course(ex_common_ids).sort_by{|course_group| course_group[:course_id]}.reverse
        @exercise_users = @exercise.all_exercise_users(current_user.id) #当前老师所在班级的全部学生
        # 获取并设置 已答人数 未答人数 试卷人数 正在考试的人数
        get_exercise_answers(@exercise_users, @exercise_status, @exercise)
      end
    else #当前为学生或者有过答题的
      @ex_user_end_time = @exercise.get_exercise_end_time(current_user.id) #当前用户所看到的剩余时间
      # 获取试卷所有已发布的分班中的考试学生
      @exercise_all_users = @exercise.get_stu_exercise_users
      # 获取并设置 已答人数 未答人数 试卷人数 正在考试的人数
      get_exercise_answers(@exercise_all_users, @exercise_status, @exercise) # 未答和已答的
      # 获取当前用户(学生)的试卷答题记录
      exercise_current_user = @exercise_all_users.exercise_commit_users(current_user.id)
      if exercise_current_user.exists? #表示为课堂学生或已回答的
        @exercise_current_user_status = 1
        if @exercise.score_open && @exercise_status == Exercise::DEADLINE #勾选了成绩公开且试卷已截止的
          all_user_ids = @exercise_all_users.pluck(:user_id)
          all_user_ids.delete(current_user.id) #删除了当前用户的ID
          @exercise_users = @exercise_all_users.exercise_commit_users(all_user_ids).distinct
          @current_user_ex_answers = exercise_current_user #当前用户的回答
        else
          @exercise_users = exercise_current_user
        end
      else #表示为未回答的，或未非课堂成员的
        @exercise_current_user_status = 2 #当前用户非课堂成员
      end
    end

    #筛选/分类,排序
    order = params[:order]
    order_type = params[:order_type] || "desc"
    if @exercise_users.present? && @exercise_users.size > 0
      @exercise_users_count = @exercise_users.size #当前显示的全部成员数量
      teacher_reviews = @exercise_users.exercise_review # 已完全评阅的
      teacher_unreviews = @exercise_users.exercise_unreview.subjective_not_reviewed #未评阅的,没有完全评阅完成,同时主观题评阅也未完成
      teacher_reviewing = @exercise_users.exercise_unreview.subjective_reviewed #评阅中的,未完全评阅完成且主观题有评阅的
      @teacher_review_count = teacher_reviews.size #已完全评阅
      @teacher_unreview_count = teacher_unreviews.size #未评阅完全的
      @teacher_reviewing_count = teacher_reviewing.size #评阅中的

      #是否评阅
      # 未评已评都勾选了
      if params[:review].present?
        review_status =  params[:review].map(&:to_i).sort
        review_ids0 = []
        review_ids1 = []
        review_ids2 = []
        if review_status != [0, 1, 2]
          # 未评阅
          if review_status.include?(0)
            review_ids0 = teacher_unreviews.pluck(:id)
          # 已评阅
            end
          if review_status.include?(1)
            review_ids1 = teacher_reviews.pluck(:id)
          end
          # 评阅中
          if review_status.include?(2)
            review_ids2 = teacher_reviewing.pluck(:id)
          end
          @exercise_users = ExerciseUser.where(id: (review_ids0 + review_ids1 + review_ids2))
        else
          @exercise_users = @exercise_users
        end
      end

      #答题状态的选择
      # 0:未开始 1:考试中 2:已交卷 3:已交卷未答
      if params[:commit_status].present?
        choose_type = params[:commit_status].map(&:to_i).reject(&:blank?)
        if choose_type.present? && choose_type.sort != [0, 1, 2, 3]
          exercise_users_list1 = exercise_users_list2 = exercise_users_list3 = exercise_users_list4 = []
          if choose_type.include?(0)
            exercise_users_list1 = @exercise_users.where(start_at: nil).pluck(:id) || []
          end
          if choose_type.include?(1)
            exercise_users_list2 = @exercise_users.none_commit.where.not(start_at: nil).pluck(:id) || []
          end
          if choose_type.include?(2)
            exercise_users_list3 = @exercise_users.commited.pluck(:id) || []
          end
          if choose_type.include?(3)
            exercise_users_list4 = @exercise_users.commit_with_no_answer.pluck(:id)|| []
          end
          @exercise_users = ExerciseUser.where(
              id: exercise_users_list1 + exercise_users_list2 + exercise_users_list3 + exercise_users_list4
          )
        end
      end

      #班级的选择
      if params[:exercise_group_id].present?
        group_id = params[:exercise_group_id]
        exercise_students = @course_all_members.course_find_by_ids("course_group_id", group_id) #试卷所分班的全部人数
        user_ids = exercise_students.pluck(:user_id).reject(&:blank?)
        @exercise_users = @exercise_users.exercise_commit_users(user_ids)
      end

      #搜索
      if params[:search].present?
        @exercise_users = @exercise_users.joins(user: :user_extension).
            where("CONCAT(lastname, firstname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%")
      end

      # 客观题分数
      if params[:objective_score_gte].present?
        @exercise_users = @exercise_users.
            where("objective_score >= :objective_score_gte", objective_score_gte: params[:objective_score_gte].to_i).
            where.not(commit_status: ExerciseUser.commit_statuses[:none_commit])
      end
      if params[:objective_score_lte].present?
        @exercise_users = @exercise_users.
            where("objective_score <= :objective_score_lte", objective_score_lte: params[:objective_score_lte].to_i).
            where.not(commit_status: ExerciseUser.commit_statuses[:none_commit])
      end

      exercise_user_joins = @exercise_users.joins(user: :user_extension)
      # 设定：
      #
      # 评阅状态有3种：已评阅、未评阅、评阅中
      #
      # 设定：
      #
      # 本表默认按评阅状态+提交状态排序，具体规则为：已交卷且未评阅>已交卷且评阅中>已交卷且已评阅>已交卷(未答)>考试中>未开始；
      #
      # 同种状态之间，以客观题得分排序；
      #
      # 无客观题得分数据，以姓名编码排序 ---- 暂时不支持
      if order == "student_id"
        @exercise_users = exercise_user_joins.order("user_extensions.student_id #{order_type}")
      elsif order == "score"
        @exercise_users = exercise_user_joins.order("#{order} #{order_type}")
      elsif order == "subjective_score"
        @exercise_users = exercise_user_joins.order("#{order} #{order_type}")
      else
        # 已交卷已答且未评阅 100
        # 已交卷且评阅中 101 201
        # 已交卷且已评阅 111 110
        # 已交卷(未答) 211 210  已交卷未答且未评阅 200
        # 考试中
        # 未开始
        @exercise_users = exercise_user_joins.
            order("(case concat(commit_status, reviewed, subjective_reviewed)
              when 100 then 0
              when 101 then 1
              when 201 then 2
              when 111 then 3
              when 110 then 4
              when 211 then 5
              when 210 then 6
              when 200 then 7
              when 000 then 8
              when 010 then 9
              when 011 then 10
              when 001 then 11
              end ) asc "
            ).order("objective_score desc")
        @exercise_users = @exercise_users.order("end_at #{order_type}, start_at #{order_type}")
      end

      @export_ex_users = @exercise_users

      @exercise_users_size = @exercise_users.size

      # 获取未分页的所有试卷用户数据
      @total_exercise_users = @exercise_users.includes(:user).
          select(:user_id, "users.lastname", "users.login", "users.id")
      # 应前端要求,在此基础上进一步将不能评阅的数据筛选掉
      @total_exercise_users = @total_exercise_users.
          where(reviewed: false, commit_status: [ExerciseUser.commit_statuses[:commited], ExerciseUser.commit_statuses[:commit_with_no_answer]])
      # 分页
      @page = params[:page] || 1
      @limit = params[:limit] || 20
      @exercise_users = @exercise_users.preload(:exercise_user_scores, user: :user_extension).page(@page).per(@limit)
      Rails.logger.info("==============================获取exercise_users完成==============================")
    else
      @exercise_users = []
      @export_ex_users = @exercise_users
      @exercise_users_size = 0
      Rails.logger.info("==============================获取exercise_users完成==============================")
    end
  end
end
