class Shixun < ApplicationRecord
  include Searchable::Shixun
  attr_accessor :page_no  #管理员页面 实训配置更新状态时，需要接受page_no参数

  # status: 0：编辑   1：申请发布   2：正式发布  3：关闭  -1：软删除
  # public: 0：未公开   1：申请公开   2：公开
  # hide_code： 隐藏代码窗口
  # code_hidden: 隐藏代码目录
  # task_pass: 跳关
  # webssh  0：不开启webssh；1：开启练习模式;  2：开启评测模式
  # trainee 实训的难度
  # vnc: VCN实训是否用于评测
  validates_presence_of :name, message: "实训名称不能为空"
  has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy
  has_many :challenge_tags, through: :challenges
	has_many :myshixuns, :dependent => :destroy
  has_many :shixun_members, dependent: :destroy
  has_many :users, through: :shixun_members
  has_many :discusses, as: :dis, dependent: :destroy
  has_many :evaluate_records, dependent: :destroy
  has_many :shixun_mirror_repositories
  has_many :mirror_repositories, through: :shixun_mirror_repositories

  has_many :shixun_schools, :dependent => :destroy
  has_many :schools, :through => :shixun_schools

  has_many :shixun_tag_repertoires, dependent: :destroy
  has_many :tag_repertoires, through: :shixun_tag_repertoires
  has_one :first_shixun_tag_repertoire, class_name: 'ShixunTagRepertoire'
  has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire,  source: :tag_repertoire

  has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
  has_many :homework_commons, through: :homework_commons_shixuns

  has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun'

  #实训的关卡
  has_many :exercise_shixun_challenges, :dependent => :destroy
  has_many :exercise_bank_shixun_challenges, :dependent => :destroy

  # 注意：这个地方是一张关联表，关联三张表（多对多关系）
  has_many :stage_shixuns, dependent: :destroy
  has_many :stages, through: :stage_shixuns
  has_many :subjects, through: :stage_shixuns

  has_one :shixun_info, dependent: :destroy

  # 第二版本库
  has_one :shixun_secret_repository, dependent: :destroy

  belongs_to :user
  # 实训服务配置
  has_many :shixun_service_configs, :dependent => :destroy
  has_many :tidings, as: :container, dependent: :destroy

  # 收藏
  has_many :collections, as: :container, dependent: :destroy

  # 实训审核记录
  has_many :shixun_reviews, -> {order("shixun_reviews.created_at desc")}, :dependent => :destroy

  has_many :laboratory_shixuns, dependent: :destroy
  belongs_to :laboratory, optional: true
  # Jupyter数据集,附件
  has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy

  # 试卷的实训题
  has_many :exercise_questions

	scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
				"%#{keyword}%", "%#{keyword}%") }

  #scope :include_user, ->(user_id) { where(id: Myshixun.where(user_id: user_id).pluck(:shixun_id))}

  scope :filter_tag, ->(tag_level, tag_id) {
    case tag_level
    when 1 #大类
      where(id: Repertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id"))
    when 2 #子类
      where(id: SubRepertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id"))
    when 3 #tag
      where(id: TagRepertoire.find(tag_id).shixun_tag_repertoires.pluck(:shixun_id))
    end
  }

  scope :visible, -> { where.not(status: -1) }
  scope :published, lambda{ where(status: 2) }
  scope :published_closed, lambda{ where(status: [2, 3]) }
  scope :none_closed, lambda{ where(status: [0, 1, 2]) }
  scope :unhidden, lambda{ where(hidden: 0, status: 2) }
  scope :publiced, lambda{ where(public: 2) }
  scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) }
  scope :find_by_ids,lambda{|k| where(id:k)}
  scope :no_jupyter,  -> { where(is_jupyter: false) }

  after_create :send_tiding

  # REDO: 
  def propaedeutics
    shixun_info.try(:propaedeutics)
  end

  def description
    shixun_info.try(:description)
  end

  def evaluate_script
    shixun_info.try(:evaluate_script)
  end

  def fork_reason
    case shixun_info.try(:fork_reason)
    when 'Shixun'
      '实训内容升级'
    when 'Course'
      '课堂教学使用'
    when 'Subject'
      '实践课程使用'
    else
      shixun_info.try(:fork_reason)
    end
  end

  def fork_identifier
    self.fork_from.nil? ? "--" : fork_shixuns.first&.identifier
  end

  def shixun_status
    status = ""
    case self.status
    when 0
      status = "编辑中"
    when 1
      status = "审核中"
    when 2
      status = "已发布"
    when 3
      status = "已关闭"
    end
    status
  end

  def is_tag_used?(id)
    tag_repertoires.map(&:id).include?(id)
  end

  # 实训用户tag
  def user_tags_name(user = User.current)
    Shixun.joins(challenges: [:challenge_tags, :games]).where(games: {status: 2, user_id: user.id}, shixuns: {id:id})
        .pluck("challenge_tags.name").uniq
  end

  # 实训关卡tag
  def challenge_tags_name
    ChallengeTag.where(challenge_id: challenges.pluck(:id)).pluck(:name).uniq
  end

  def repo_path
    "#{repo_name}.git"
  end

  # 实训对应的镜像主类别名（已选）
  def main_mirror_name
    mirror_repositories.published_main_mirror.first.try(:type_name) || ""
  end

  def main_mirror_id
    mirror_repositories.published_main_mirror.first.try(:id) || -1
  end

  # 实训对应的镜像小类别名（已选）
  def small_mirror_name
    names = mirror_repositories.small_mirror.map(&:type_name)
    names.blank? ? [] : names
  end

  def small_mirror_id
    mirror_repositories.published_small_mirror.map(&:id)
  end

  # 实训镜像名
  def mirror_name
    names = mirror_repositories.map(&:type_name)
    names.blank? ? '' : names
  end

  def script_tag
    return unless mirror_script_id

    MirrorScript.find_by_id(mirror_script_id)
  end

  def standrad_script
    mirrors_id = mirror_repositories.map(&:id)
    mirror_scripts = MirrorScript.where(mirror_repository_id: mirrors_id)
    mirror_scripts.map { |ms| { scptname: ms.script_type, id: ms.id } }
  end

  def owner
    User.find_by_id(self.user_id)
  end

  def shixun_main_name
    self.mirror_repositories.published_main_mirror.first.try(:type_name)
  end

  def is_published?
    status > 1
  end

  # 当前用户开启的实训
  def current_myshixun(user_id)
    myshixuns.find_by(user_id: user_id)
  end

  # 实训技术平台
  def show_shixun_mirror
    mirror_repositories.map(&:type_name).join(';')
  end

  # 实训评分 cnt-评分次数 sum-总评分
  def shixun_preference
    game_star_info = Game.find_by_sql("select g.star from
                                         (games g left join (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id)
                                         where g.star != 0 and s.id = #{self.id}")
    if game_star_info.present?
      cnt = game_star_info.count
      sum = game_star_info.sum(&:star).to_f
      (sum / cnt.to_f).round(1)
    else
      5.0
    end
  end

  # 实训评分信息
  # return [实训评分， 5星评分比例， 4星评分比例， 3星评分比例， 2星评分比例， 1星评分比例]
  def shixun_preference_info
    game_star_info = Game.joins(challenge: :shixun).where(shixuns: {id: id}).where.not(games: {star: 0}).pluck(:star)
    star_info = []
    if game_star_info.present?
      5.downto(1) do |i|
        star_info << ((game_star_info.select{|s| s == i}.count / game_star_info.count.to_f) * 100).round
      end
      sum = star_info.sum
      max = star_info.max
      # 四舍五入引起5星比例超过100%， 将最大的比例的评分做出调整
      if sum > 100
        star_info = star_info.map{|s| s == max ? s - 1 : s}
      elsif sum < 100
        star_info = star_info.map{|s| s == max ? s + 1 : s}
      end
      cnt = game_star_info.count
      sum = game_star_info.sum
      star_info.unshift((sum / cnt.to_f).round(1))
    else
      star_info = [5.0, 100, 0, 0, 0, 0]
    end

    star_info
  end


  # 实训关卡的总分(由于大部分是实践题,因此没关联查choose表)
  # 提前加载问题：由于选择题比较少，所以几乎不会触发选择题的查询，所以没必要提前载入choose_score
  def all_score
    self.challenges.sum(:score)
  end

  ### fork 数量
  def fork_count
    self.class.where(fork_from: id).count
  end

  # 学员等级
  def shixun_trainee
    case trainee
    when 1 then '初级学员'
    when 2 then '中级学员'
    when 3 then '中高级学员'
    when 4 then '高级学员'
    else ''
    end
  end

  def shixun_level
    case trainee
    when 1 then '初级'
    when 2 then '中级'
    when 3 then '中高级'
    when 4 then '高级'
    else ''
    end
  end

  # 纯选择提类型
  def is_choice_type?
    challenges_count == challenges.where(st: 1).count
  end

  # 实训受用学校个数
  def school_count
    UserExtension.find_by_sql("select count(distinct ue.school_id) school_count from user_extensions ue right join myshixuns
    on ue.user_id = myshixuns.user_id where myshixuns.shixun_id = #{self.id}").first.try(:school_count).to_i
  end

  def has_manager?(user)
    return true if user.admin? || user.business?

    shixun_members.where(role: [1, 2]).exists?(user_id: user.id)
  end

  def finished_challenges_count(user)
    Game.joins(:myshixun).where(user_id: user.id, status: 2, myshixuns: { shixun_id: id }).count
  end

  def has_web_route?
    self.mirror_name.include?('JavaWeb') || self.mirror_name.include?('PHP') && self.mirror_name.include?('Mysql') || self.mirror_name.include?('Web')
  end

  # 所属实践课程
  def relation_path
    subjects.visible.unhidden.uniq
  end

  private

  def send_tiding
    self.tidings << Tiding.new(:user_id => user_id, :trigger_user_id => 1, :belong_container_id => id, :belong_container_type =>'Shixun', :tiding_type => "System", :viewed => 0)
  end

end
