class HacksController < ApplicationController
  before_action :require_login, except: [:index]
  before_action :require_teacher_identity, only: [:create, :edit, :update]
  before_action :require_auth_identity, only: [:update, :edit, :publish]
  before_action :find_hack, only: [:edit, :update, :publish, :start]

  # 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可
  def start
    # 未发布的编程题,只能作者、或管理员访问
    start_hack_auth
    user_hack = @hack.hack_user_lastest_codes.mine(current_user.id)
    identifier =
        if user_hack.present?
          user_hack.identifier
        else
          user_identifier = generate_identifier HackUserLastestCode, 12
          user_code = {user_id: current_user.id, code: @hack.code,
                       identifier: user_identifier, language: @hack.language}
          @hack.hack_user_lastest_codes.create!(user_code)
          user_identifier
        end
    render_ok(data: {identifier: identifier})
  end

  # 首页
  def index
    # 筛选过滤与排序
    params_filter_or_order
    # 我解决的编程题数
    user_codes =  HackUserLastestCode.mine(current_user).passed.joins(:hack)
    @simple_count = user_codes.where(hacks: {difficult: 1}).count
    @medium_count = user_codes.where(hacks: {difficult: 2}).count
    @diff_count  = user_codes.where(hacks: {difficult: 3}).count
    @pass_count = @simple_count + @medium_count + @diff_count

    @hacks_count = @hacks.count("hacks.id")
    @hacks = paginate @hacks
  end

  def create
    begin
      logger.info("##########{hack_params}")
      hack = Hack.new(hack_params)
      ActiveRecord::Base.transaction do
        hack.user_id = current_user.id
        hack.identifier = generate_identifier Hack, 8
        hack.save!
        # 创建测试集与代码
        hack.hack_sets.create!(hack_sets_params)
        hack.hack_codes.create!(hack_code_params)
      end
      render_ok({identifier: hack.identifier})
    rescue Exception => e
      logger.error("########create_hack_error: #{e.message}")
      render_error("创建失败")
    end
  end

  def update
    begin
      ActiveRecord::Base.transaction do
        @hack.update_attributes!(hack_params)
        set_ids = @hack.hack_sets.pluck(:id)
        # 更新
        param_update_sets params[:update_hack_sets], set_ids
        # 新建
        @hack.hack_sets.create!(hack_sets_params)
        # 更新代码
        @hack.hack_codes.create!(hack_code_params)
      end
      render_ok
    rescue Exception => e
      logger.error("####update_hack_error: #{e.message}")
      render_error("更新失败")
    end
  end

  # 发布功能
  def publish
    @hack.update_attribute(:status, 1)
    render_ok
  end

  # 发布列表
  def unpulished_list
    limit = params[:limit] || 16
    page = params[:page] || 1
    hacks = Hack.where(user_id: current_user.id, status: 0)
    @hacks_count = hacks.count
    @hacks = hacks.includes(:hack_sets).page(page).per(limit)
  end

  def edit;end

  private
  # 实名认证老师,管理员与运营人员权限
  def require_teacher_identity
    unless current_user.certification_teacher? || admin_or_business?
      tip_exception(403, "..")
    end
  end

  # 只有自己,或者管理员才能更新
  def require_auth_identity
    unless @hack.user_id == current_user.id || admin_or_business?
      tip_exception(403, "..")
    end
  end

  def find_hack
    @hack = Hack.find_by_identifier(params[:identifier])
  end

  def hack_params
    params.require(:hack).permit(:name, :description, :difficult, :category, :open_or_not, :time_limit, :score)
  end

  def hack_sets_params
    params.permit(hack_sets: [:input, :output, :position])[:hack_sets]
  end

  def hack_code_params
    params.require(:hack_codes).permit(:code, :language)
  end

  def publish_params
    params.require(:hack).permit(:difficult, :category, :open_or_not, :time_limit, :score)
  end

  def param_update_sets sets, all_sets_id
    delete_set_ids = all_sets_id - sets.map{|set|set[:id]}
    @hack.hack_sets.where(id: delete_set_ids).destroy_all
    sets.each do |set|
      if all_sets_id.include?(set[:id])
        update_attrs = {input: set[:input], output: set[:output], position: set[:position]}
        @hack.hack_sets.find_by!(id: set[:id]).update_attributes(update_attrs)
      end
    end
  end

  def params_filter_or_order
    # 如果有来源,就不管发布公开私有
    select_sql = "hacks.*, if(hacks.hack_user_lastest_codes_count=0, 0, hacks.pass_num/hacks.hack_user_lastest_codes_count) passed_rate"
    if params[:come_from]
      hacks = Hack.select(select_sql).mine(current_user.id)
    else
      hacks = Hack.select(select_sql).published.opening
    end
    # 搜索
    if params[:search]
      hacks = hacks.where("name like ?", "%#{params[:search]}%")
    end
    # 难度
    if params[:difficult]
      hacks = hacks.where(difficult:  params[:difficult])
    end
    # 状态
    if params[:status]
      user_hacks = HackUserLastestCode.where(user_id: current_user.id)
      if params[:status].to_i == -1
        if user_hacks.present?
          hacks = hacks.where.not(id: user_hacks.pluck(:hack_id))
        end
      else
        hacks = hacks.joins(:hack_user_lastest_code).where(hack_user_lastest_code: {status: params[:status]})
      end
    end
    # 排序
    sort_by = params[:sort_by] || "hack_user_lastest_codes_count"
    sort_direction = params[:sort_direction] || "desc"
    @hacks = hacks.order("#{sort_by} #{sort_direction}")
  end

  def start_hack_auth
    return true if @hack == 1
    require_auth_identity
  end


end