class SubjectsController < ApplicationController
  before_action :require_login, :check_auth, except: [:index, :show, :right_banner]
  # before_action :check_auth, except: [:index]
  before_action :check_account, except: [:index, :show, :right_banner]
  before_action :find_subject, except: [:index, :create, :new, :append_to_stage, :add_shixun_to_stage]
  before_action :allowed, only: [:update, :edit, :destroy, :publish, :cancel_publish, :cancel_has_publish, :apply_public,
                                 :search_members, :add_subject_members, :statistics, :shixun_report, :school_report,
                                 :cancel_has_public, :up_member_position, :down_member_position, :update_team_title,
                                 :statistics_info]
  before_action :require_admin, only: [:copy_subject]
  before_action :shixun_marker, only: [:add_shixun_to_stage]


  include ApplicationHelper
  include SubjectsHelper
  include GitCommon
  include CustomSortable

  def index
    subjects = Weapps::SubjectQuery.call(current_laboratory, params, "web")
    @subject_count = subjects.map(&:id).size
    @subjects = paginate subjects.includes(:shixuns, :repertoire)
  end

  def show
    @user = current_user
    @is_creator = current_user.creator_of_subject?(@subject)
    @is_manager = @user.manager_of_subject?(@subject)

    # 合作团队
   # @shixuns = @subject.shixuns.published.pluck(:id)
    @courses = @subject.courses if @subject.excellent
    @members = @subject.subject_members.includes(:user)

    # 访问数变更
    @subject.increment!(:visits)
  end

  def right_banner
    @user = current_user
    # 合作团队
    @members = @subject.subject_members.includes(:user)
    shixuns = @subject.shixuns.published.pluck(:id)
    challenge_ids = Challenge.where(shixun_id: shixuns).pluck(:id)
    # 实训路径中的所有实训标签
    @tags = ChallengeTag.where(challenge_id: challenge_ids).pluck(:name).uniq
    # 用户获取的实训标签
    # @user_tags = @subject.shixuns.map(&:user_tags_name).flatten.uniq

    # 用户进展
    user_subject_progress(challenge_ids)
  end

  def new
    normal_status("")
  end

  def create
    ActiveRecord::Base.transaction do
      begin
        @subject = Subject.new(subject_params)
        @subject.user_id = current_user.id
        @subject.save!
        @subject.subject_members.create!(role: 1, user_id: current_user.id)

        # 将实践课程标记为该云上实验室建立
        Laboratory.current.laboratory_subjects.create!(subject: @subject, ownership: true)
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception("实训路径创建失败")
        raise ActiveRecord::Rollback
      end
    end
  end

  def edit
  end

  def update
    begin
      @subject.update_attributes(subject_params)
    rescue Exception => e
      uid_logger_error(e.message)
      tip_exception("实训路径更新失败")
      raise ActiveRecord::Rollback
    end
  end

  def destroy
    ActiveRecord::Base.transaction do
      begin
        ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).destroy_all
        @subject.destroy
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception("实训路径删除失败")
        raise ActiveRecord::Rollback
      end
    end
  end

  def choose_subject_shixun
    @search = params[:search].strip if params[:search]
    @type = params[:type]
    # 超级管理员用户显示所有未隐藏的实训、非管理员显示合作团队用户的实训（对本单位公开且未隐藏）
    if current_user.admin?
      @shixuns = Shixun.select([:id, :name, :status, :myshixuns_count, :identifier, :averge_star]).where(hidden: 0)
    else
      none_shixun_ids = ShixunSchool.where("school_id != #{current_user.user_extension.try(:school_id).to_i}").pluck(:shixun_id)
      @shixuns = Shixun.select([:id, :name, :status, :myshixuns_count, :identifier, :averge_star]).where.not(id: none_shixun_ids).where(hidden: 0)
    end

    # 实训课程的所有标签
    tag_ids = @shixuns.joins(:shixun_tag_repertoires).pluck(:tag_repertoire_id).uniq
    @tags = TagRepertoire.select([:id, :name]).where(id: tag_ids)

    unless params[:search].blank?
      @shixuns = @shixuns.joins(:user).where("shixuns.name like ? or concat(users.lastname, users.firstname) like ?",
                                             "%#{@search}%", "%#{@search}%").distinct
    end

    unless @type.nil? || @type == "" || @type == "all"
      shixun_ids = ShixunTagRepertoire.where(tag_repertoire_id: @type).pluck(:shixun_id).uniq
      @shixuns = @shixuns.where(id: shixun_ids)
    end

    @shixuns = @shixuns.reorder("created_at desc")
    @shixuns_count = @shixuns.size

    ## 分页参数
    page  = params[:page] || 1
    @shixuns = @shixuns.page(page).per(10)

    @shixuns = @shixuns.includes(:myshixuns)
  end

  def append_to_stage
    order_ids = params[:shixun_id].size > 0 ? params[:shixun_id].join(',') : -1
    @shixuns = Shixun.where(id: params[:shixun_id]).order("field(id, #{order_ids})")
  end

  # 添加实训项目
  def add_shixun_to_stage
    identifier = generate_identifier Shixun, 8
    ActiveRecord::Base.transaction do
      @shixun = Shixun.create!(name: params[:name], user_id: current_user.id, identifier: identifier, is_jupyter: params[:is_jupyter])
      # 添加合作者
      @shixun.shixun_members.create!(user_id: current_user.id, role: 1)
      # 创建长字段
      ShixunInfo.create!(shixun_id: @shixun.id, description: "请在此处添加实训描述")
      # 创建版本库
      repo_path = repo_namespace(current_user.login, identifier)
      GitService.add_repository(repo_path: repo_path)
      # todo: 为什么保存的时候要去除后面的.git呢??
      @shixun.update_column(:repo_name, repo_path.split(".")[0])
      mirror_id =
          if @shixun.is_jupyter?
            folder = EduSetting.get('shixun_folder')
            path = "#{folder}/#{identifier}"
            FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
            MirrorRepository.where("type_name like '%Jupyter%'").first&.id
          else
            MirrorRepository.find_by(type_name: 'Python3.6')&.id
          end
      if mirror_id
        ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror_id)
        @shixun.shixun_service_configs.create!(:shixun_id => @shixun.id, :mirror_repository_id =>  mirror_id)
      end
    end
  end

  def choose_course
    course_ids = Course.find_by_sql("SELECT c.id FROM courses c, course_members m
                                      WHERE m.course_id = c.id AND m.role in (1,2,3)
                                      AND m.user_id=#{current_user.id} AND c.is_delete = 0 AND c.is_end = 0").map(&:id)
    @courses = Course.where(id: course_ids)
    ## 云上实验室过滤
    @courses = @courses.where(id: current_laboratory.all_courses)

    @all_shixun_ids = @subject.shixuns.where(use_scope: 0).pluck(:id) +
      @subject.shixuns.joins(:shixun_schools).where("school_id = #{current_user.user_extension.try(:school_id).to_i} and use_scope = 1").pluck(:id)
  end

  def send_to_course
    @course = Course.find_by!(id: params[:course_id])
    stages = @subject.stages.where(id: @subject.stage_shixuns.where(shixun_id: params[:shixun_ids]).pluck(:stage_id)).reorder("stages.position DESC")
    order_ids = params[:shixun_ids].size > 0 ? params[:shixun_ids].reverse.join(',') : -1
    course_module = @course.course_modules.where(module_type: "shixun_homework").first
    homework_ids = []

    ActiveRecord::Base.transaction do
      # 将实训课程下的所有已发布实训按顺序发送到课堂，同时创建与章节同名的实训作业目录
      stages.each do |stage|
        category = CourseSecondCategory.where(name: stage.name, course_id: @course.id, category_type: "shixun_homework").first ||
            CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework",
                                         course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)

        shixuns = stage.shixuns.no_jupyter.published.where(id: params[:shixun_ids]).reorder("field(shixuns.id, #{order_ids})")
        shixuns.each do |shixun|
          homework = HomeworksService.new.create_homework shixun, @course, category, current_user
          homework_ids << homework.id
        end
      end
    end
    homework_ids.each do |homework_id|
      CreateStudentWorkJob.perform_later(homework_id)
    end
  end

  def publish
    @subject.update_attributes(status: 2)
  end

  def cancel_publish
    begin
      apply = ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).order("created_at desc").first
      if apply && apply.status == 0
        apply.update_attributes(status: 3)
        apply.tidings.destroy_all
      end
      @subject.update_attributes(status: 0)
    rescue => e
      uid_logger_error(e.message)
      tip_exception("撤销申请失败")
    end
  end

  def cancel_has_publish
    begin
      @subject.update_attributes(:status => 0)
    rescue => e
      uid_logger_error(e.message)
      tip_exception("撤销发布失败")
      raise ActiveRecord::Rollback
    end
  end

  # 申请公开
  def apply_public
    tip_exception(-1, "请先发布课程再申请公开") if @subject.status != 2
    apply = ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).order("created_at desc").first
    if apply && apply.status == 0
      @status = 0
    else
      @subject.update_attributes(public: 1)
      ApplyAction.create(container_type: "ApplySubject", container_id: @subject.id, user_id: current_user.id, status: 0)
      begin
        Educoder::Sms.send(mobile: '17347001317', send_type:'publish_subject' , name: '管理员')
      rescue => e
        uid_logger_error("发送验证码出错: #{e}")
      end
      @status = 1
    end
  end

  def cancel_public
    # 仅限创建者或管理员
    return normal_status(403, "") unless current_user.creator_of_subject?(@subject)
    begin
      apply = ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).order("created_at desc").first
      if apply && apply.status == 0
        apply.update_attributes(status: 3)
        apply.tidings.destroy_all
      end
      @subject.update_attributes(public: 0)
      render_ok
    rescue => e
      uid_logger_error(e.message)
      tip_exception("撤销申请失败")
    end
  end

  def cancel_has_public
    begin
      @subject.update_attributes(:public => 0)
      render_ok
    rescue => e
      uid_logger_error(e.message)
      tip_exception("撤销公开失败")
    end
  end

  def update_team_title
    tip_exception("team_title参数不能为空") if params[:team_title].blank?
    @subject.update_attributes!(team_title: params[:team_title])
    normal_status("更新成功")
  end

  def search_members
    tip_exception("搜索内容不能为空") unless params[:search]
    page = params[:page] || 1
    member_ids = @subject.subject_members.map(&:user_id).join(',')
    condition = "%#{params[:search].strip}%".gsub(" ","")
    @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, ifnull(firstname, ''), login)) LIKE ?", member_ids, "#{condition}")
    @users = @users.where(laboratory_id: current_laboratory.id) unless current_laboratory.main_site?

    @users = @users.page(page).per(10)
    @users = @users.includes(:user_extension)
  end

  def add_subject_members
    # tip_exception(403, "没权限操作") if !current_user.admin?
    tip_exception("user_ids 不能为空!") if params[:user_ids].blank?
    memberships = params[:user_ids]
    memberships.each do |member|
      if SubjectMember.where(user_id: member, subject_id: @subject.id).count == 0
        user = User.find_by!(id: member)
        SubjectMember.create!(user_id: member, subject_id: @subject.id, role: 2, position: @subject.subject_members.size + 1) if user.present?
      end
     end
  end

  # 删除实训
  # DELETE: /api/subejcts/:id/delete_member
  def delete_member
    tip_exception(403, "没权限操作") unless current_user.manager_of_subject?(@subject)
    tip_exception('用户id不能为空') if params[:user_id].blank?
    return tip_exception("教学团队需要保留一位成员") if @subject.subject_members.count == 1
    user = @subject.subject_members.find_by(user_id: params[:user_id])
    tip_exception("该成员不存在") if user.blank?
    ActiveRecord::Base.transaction do
      begin
        @subject.subject_members.where("position > #{user.position}").update_all("position = position - 1")
        user.destroy!
        @subject.subject_members.order('position').first.update(role: user.role) if user.role == 1
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception(e.message)
        raise ActiveRecord::Rollback
      end
    end
  end

  # 合作者上移
  def up_member_position
    tip_exception('用户id不能为空') if params[:user_id].blank?
    ActiveRecord::Base.transaction do
      begin
        member = @subject.subject_members.where(user_id: params[:user_id]).first
        # position为1时不能再往上移
        tip_exception('不能再上移了') if member.position == 1

        up_member = @subject.subject_members.where(position: member.position - 1).first
        up_member.update_attribute(:position, member.position)
        member.update_attribute(:position, member.position - 1)
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception(e.message)
        raise ActiveRecord::Rollback
      end
    end
  end

  # 合作者下移
  def down_member_position
    tip_exception('用户id不能为空') if params[:user_id].blank?
    ActiveRecord::Base.transaction do
      begin
        member = @subject.subject_members.where(user_id: params[:user_id]).first

        # position已经是最大值时不能再往下移
        tip_exception('不能再下移了') if member.position == @subject.subject_members.size

        down_member = @subject.subject_members.where(:position => member.position + 1).first
        down_member.update_attribute(:position, member.position)
        member.update_attribute(:position, member.position + 1)
      rescue Exception => e
        uid_logger_error(e.message)
        tip_exception(e.message)
        raise ActiveRecord::Rollback
      end
    end
  end

  def statistics
    @learn_count = @subject.member_count
    shixun_ids = @subject.stage_shixuns.pluck(:shixun_id)
    # 受用课堂（已经发布的实训（在此路径中的实训）作业的个数）
    homework_common_id = HomeworkCommonsShixun.where(shixun_id: shixun_ids).pluck(:homework_common_id).uniq
    homework_common_id = homework_common_id.blank? ? -1 : homework_common_id.join(",")

    courses = Course.find_by_sql("select c.id, c.school_id from courses c right join homework_commons hc on c.id = hc.course_id where c.is_delete = 0
                  and c.school_id is not null and hc.publish_time < '#{Time.now}' and hc.id in (#{(homework_common_id)})")
    course_ids = courses.pluck(:id).uniq
    @course_count = course_ids.length
    # 受用院校
    school_ids = courses.pluck(:school_id).uniq
    @schools_count = school_ids.length

    # 采用课堂情况
    @schools = School.select([:id, :name]).where(id: school_ids)
    @schools =
        @schools.map do |s|
          school_courses = Course.where(id: course_ids, school_id: s.id)
          course_count = school_courses.count
          student_count = CourseMember.where(course_id: school_courses.pluck(:id), role: 4).count
          homework_count = HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id
                                           where c.school_id = #{s.id} and hc.id in(#{homework_common_id})").first.try(:cnt)
          s.attributes.dup.merge({name: s.name, course_count: course_count, student_count: student_count,homework_count: homework_count})
        end
    @schools = @schools.sort{|x,y| y['homework_count'] <=> x['homework_count']}
    @school_total_count = @schools.size

    page = params[:page] || 1
    @schools = @schools[(page.to_i-1)*10, 10]

    # TODO: 这个可以异步加载，让页面刷新完成后再加载图形数据
    # 章节使用情况
    @stage_user_info = []
    @sum = 0 #总数
    @subject.stages.includes(:stage_shixuns).each do |stage|
      shixun_ids = stage.stage_shixuns.pluck(:shixun_id)
      if shixun_ids.present?
        homework_common_id = HomeworkCommonsShixun.where(shixun_id: shixun_ids).pluck(:homework_common_id).uniq
        if homework_common_id.present?
          publish_homework  = HomeworkDetailManual.where("homework_common_id in(?) and comment_status > 0", homework_common_id.join(",")).pluck(:homework_common_id)
          use_count = publish_homework.present? ? HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id
                                            where hc.id in(#{publish_homework.join(",")}) and c.school_id is not null").first.try(:cnt) : 0
          @sum += use_count
        else
          @sum += 0
          use_count = 0
        end
        @stage_user_info << use_count
      else
        @sum += 0
        @stage_user_info << 0
      end
    end
  end

  def statistics_info
    @data =
        if params[:type] == "shixun_info"
          @subject.subject_shixun_infos
        elsif params[:type] == "user_info"
          @subject.subject_user_infos
        else
          select_sql = "id, count(subject_course_records.id) total, sum(course_count) course_count, sum(student_count) student_count, " +
              "sum(choice_shixun_num) choice_shixun_num, sum(choice_shixun_frequency) choice_shixun_frequency"
          @total = @subject.subject_course_records.select("#{select_sql}").first
          @subject.subject_course_records
        end

    @data_count = @data.count
    if params[:sort_by].present?
      sort_direction = params[:sort_direction].present? ? params[:sort_direction] : "desc"
      sort_by = params[:sort_by]
      @data = @data.order("#{sort_by} #{sort_direction}")
    end
    ## 分页参数
    page  = params[:page]  || 1
    limit = params[:limit] || 16
    @data = @data.page(page).per(limit)
  end

  def shixun_report

  end

  def school_report
    @schools = School.find_by_sql("select count(ms.id) ue_count, s.id, s.name school_name from user_extensions ue,
                                  myshixuns ms, schools s where ue.user_id = ms.user_id and ms.shixun_id in (select shixun_id from
                                  stage_shixuns where subject_id = '#{@subject.id}') and s.id = ue.school_id group by ue.school_id
                                  order by ue_count desc limit 10")
  end

  # 预约报名
  def appointment
    tip_exception("还存在未结束的课堂") unless @subject.max_course_end_date.nil? || @subject.max_course_end_date < Date.today
    tip_exception("无需重复报名") if @subject.subject_appointments.exists?(user_id: current_user.id)
    ActiveRecord::Base.transaction do
      @subject.subject_appointments << SubjectAppointment.new(user_id: current_user.id)
      @subject.increment!(:participant_count)
      if @subject.participant_count == @subject.student_count
        @subject.start_course_notify
      end
      normal_status("预约成功")
    end
  end


  # 复制实践课程
  def copy

  end


  private
  def subject_params
    tip_exception("实训路径名称不能为空") if params[:name].blank?
    tip_exception("实训路径简介不能为空") if params[:description].blank?
    tip_exception("实训路径学习须知不能为空") if params[:learning_notes].blank?
    params.require(:subject).permit(:name, :description, :learning_notes)
  end

  def find_subject
    @subject = Subject.find_by!(id: params[:id])

    unless @subject.status == 2 || current_user.manager_of_subject?(@subject)
      tip_exception("403", "")
    end
  end

  def allowed
    unless current_user.manager_of_subject?(@subject)
      tip_exception("403", "")
    end
  end

  # 用户进展和获取的标签
  def user_subject_progress challenge_ids
    pass_games = Game.select(:id, :cost_time, :challenge_id).where(status: 2, user_id: current_user.id, challenge_id: challenge_ids) if current_user.logged?

    @all_score = Challenge.where(id: challenge_ids).size
    # 如果没有通关的，没必要再继续统计了
    if pass_games.blank?
      @my_score = 0
      @learned = 0
      @time = 0
      @user_tags = []
    else
      pass_challenge_ids = pass_games.map(&:challenge_id).uniq # 按道理是不用去重的，但是历史数据与重复
      # subject_challenge_count = @subject.shixuns.sum(:challenges_count)
      # 用户通关获得的标签
      @user_tags = ChallengeTag.where(challenge_id: pass_challenge_ids).pluck(:name)
      # 用户学习进度
      @learned =
        @all_score == 0 ? 0 :
              ((pass_challenge_ids.size.to_f / @all_score).round(2) * 100).to_i
      # 用户通关分数
      @my_score = Challenge.where(id: pass_challenge_ids).size
      @time = pass_games.map(&:cost_time).sum
    end


  end



end
