
namespace :competition do
  desc "statistic gcc_course competition score"
  task :extra_course_statistic, [:end_time] => :environment do |_, args|
    end_time = Time.parse(args[:end_time])
    start_time = Time.parse('2018-06-01')

    old_competition = Competition.find 9
    competition = Competition.find 13

    old_competition_user_ids = old_competition.team_members.pluck(:user_id)

    student_count_subquery = CourseMember.where('course_id = courses.id AND role = 4').select('count(*)').to_sql
    subquery = StudentWork.where('homework_common_id = hcs.id')
                 .select('sum(compelete_status >0 ) as finish, count(*) as total')
                 .having('total != 0 and finish >= (total / 2)').to_sql
    shixun_user_ids = Shixun.where.not(user_id: old_competition_user_ids).where(status: 2).where('shixuns.created_at > ? && shixuns.created_at <= ?', start_time, end_time).pluck(:user_id).uniq
    course_user_ids = Course.where.not(tea_id: old_competition_user_ids).where('courses.created_at > ?', start_time)
                        .where('courses.created_at <= ?', end_time)
                        .where("(#{student_count_subquery}) >= 3")
                        .where("exists(select 1 from homework_commons hcs where hcs.course_id = courses.id and hcs.publish_time is not null and hcs.publish_time < ? and hcs.homework_type = 4 and exists(#{subquery}))", end_time)
                        .joins('join course_members on course_members.course_id = courses.id and course_members.role in (1,2,3)').pluck(:tea_id)

    user_ids = shixun_user_ids + course_user_ids

    users = User.joins(:user_extension).where(id: user_ids).where(user_extensions: {identity: 0})

    competition.competition_teams.destroy_all

    users.each do |user|
      team = CompetitionTeam.create!(competition_id: competition.id, user_id: user.id, name: user.real_name)
      TeamMember.create!(competition_team_id: team.id, user_id: user.id, role: 1, competition_id: competition.id)
    end

    custom_logger("Start Statistic Competition Score ~")

    custom_logger("Clear Old Competition Scores ~")
    CompetitionScore.where(competition_id: competition.id).delete_all
    CompetitionCourseRecord.where(competition_id: competition.id).delete_all
    custom_logger("Clear Old Competition Scores Completed!")

    CompetitionTeam.where(competition_id: competition.id).each do |team|
      custom_logger("Start Statistic Competition Team: #{team.id}|#{team.name} ~")
      team_user_ids = team.team_members.pluck(:user_id)
      total_score = 0

      # =========== Shixun ===========
      shixuns = Shixun.where(user_id: team_user_ids, status: 2)
                  .where('shixuns.created_at > ? && shixuns.created_at <= ?', start_time, end_time)
      shixuns = shixuns.joins('left join shixuns forked_shixuns on forked_shixuns.fork_from = shixuns.id and forked_shixuns.status = 2')
      shixuns = shixuns.select('shixuns.id, shixuns.identifier, shixuns.user_id, shixuns.myshixuns_count, shixuns.name, shixuns.fork_from, sum(forked_shixuns.myshixuns_count) forked_myshixun_count')
      shixuns = shixuns.group('shixuns.id').order('shixuns.myshixuns_count desc').includes(:user)

      shixun_ids = shixuns.map(&:id)
      myshixun_count_map = get_valid_myshixun_count(shixun_ids)
      original_myshixun_count_map = myshixun_count_map.clone
      # forked shixun valid myshixun count
      forked_shixun_map = Shixun.where(status: 2, fork_from: shixun_ids).select('id, fork_from')
      forked_shixun_map = forked_shixun_map.each_with_object({}) { |sx, obj| obj[sx.id] = sx.fork_from }
      forked_myshixun_count_map = get_valid_myshixun_count(forked_shixun_map.keys)
      forked_myshixun_count_map.each { |k, v| myshixun_count_map[forked_shixun_map[k]] = myshixun_count_map[forked_shixun_map[k]].to_i + v.to_i }

      course_count_map = get_valid_course_count(shixun_ids, end_time)
      forked_map = get_valid_course_count(forked_shixun_map.keys, end_time)
      forked_course_count_map = {}
      forked_map.each do |forked_id, course_count|
        forked_course_count_map[forked_shixun_map[forked_id]] ||= 0
        forked_course_count_map[forked_shixun_map[forked_id]] += course_count
      end

      custom_logger("Start Shixun Score ~")
      shixuns.each do |shixun|
        valid_course_count = course_count_map.fetch(shixun.id, 0)
        valid_student_count = original_myshixun_count_map.fetch(shixun.id, 0)
        score =
          if shixun.fork_from.blank?
            500 + 50 * valid_course_count + 10 * valid_student_count
          else
            100 + 10 * valid_course_count + 5 * valid_student_count
          end

        forked_shixun_map.each do |shixun_id, fork_from_id|
          next if fork_from_id != shixun.id

          score += 100 + 10 * forked_map.fetch(shixun_id, 0) + 5 * forked_myshixun_count_map.fetch(shixun_id, 0)
        end

        total_score += score

        attr = {
          competition_id: competition.id,
          competition_team_id: team.id,
          user_id: shixun.user.id,
          username: shixun.user.show_real_name,
          score: score,
          type: 'CompetitionCourseShixunRecord',
          snapshot: {
            shixun: shixun.as_json(only: [:id, :name, :identifier, :fork_from]),
            myshixuns_count: shixun.myshixuns_count.to_i,
            forked_myshixun_count: shixun['forked_myshixun_count'].to_i,
            valid_myshixun_count: myshixun_count_map.fetch(shixun.id, 0),
          }
        }
        CompetitionCourseRecord.create(attr)
      end
      custom_logger("Shixun Score Completed!")


      # =========== Course ===========
      student_count_subquery = CourseMember.where('course_id = courses.id AND role = 4').select('count(*)').to_sql
      subquery = StudentWork.where('homework_common_id = hcs.id')
                   .select('sum(compelete_status >0 ) as finish, count(*) as total')
                   .having('total != 0 and finish >= (total / 2)').to_sql
      course_ids = Course.where('courses.created_at > ?', start_time)
                     .where('courses.created_at <= ?', end_time)
                     .where("(#{student_count_subquery}) >= 3")
                     .where("exists(select 1 from homework_commons hcs where hcs.course_id = courses.id and hcs.publish_time is not null and hcs.publish_time < ? and hcs.homework_type = 4 and exists(#{subquery}))", end_time)
                     .joins('join course_members on course_members.course_id = courses.id and course_members.role in (1,2,3)')
                     .where(course_members: { user_id: team_user_ids }).pluck(:id)
      courses = Course.where(id: course_ids).joins(:practice_homeworks).where('homework_commons.publish_time < ?', end_time)
      courses = courses.select('courses.id, courses.name, courses.members_count, count(*) shixun_homework_count')
                   .group('courses.id').order('shixun_homework_count desc').having('shixun_homework_count > 0')

      course_ids = courses.map(&:id)
      course_myshixun_map = Myshixun.joins(student_works: :homework_common)
                               .where(homework_commons: { course_id: course_ids })
                               .where('exists(select 1 from games where games.myshixun_id = myshixuns.id and games.status = 2)')
                               .group('homework_commons.course_id').count
      course_shixun_count_map = get_valid_shixun_count(course_ids, end_time)

      custom_logger("Start Course Score ~")
      courses.each do |course|
        user = course.teachers.where(user_id: team_user_ids).first.user

        score = 500 + 5 * course_shixun_count_map.fetch(course.id, 0) * course_myshixun_map.fetch(course.id, 0)
        total_score += score

        attr = {
          competition_id: competition.id,
          competition_team_id: team.id,
          user_id: user.id,
          username: user.show_real_name,
          score: score,
          type: 'CompetitionCourseCourseRecord',
          snapshot: {
            course: course.as_json(only: [:id, :name]),
            members_count: course.students.count.to_i,
            shixun_homework_count: course['shixun_homework_count'].to_i,
            valid_myshixun_count: course_myshixun_map.fetch(course.id, 0),
          }
        }
        CompetitionCourseRecord.create(attr)
      end
      custom_logger("Course Score Completed!")

      custom_logger('Create Competition Score ~')
      CompetitionScore.create(user_id: team.user_id, competition_team_id: team.id, competition_id: competition.id, score: total_score)

      custom_logger("Statistic Competition Team: #{team.id}|#{team.name} Completed!")
    end
  end

  def custom_logger(msg)
    Rails.logger.info(msg)
    p msg
  end

  def get_valid_myshixun_count(ids)
    Myshixun.where(shixun_id: ids)
      .where('exists(select 1 from games where games.myshixun_id = myshixuns.id and games.status = 2)')
      .group('shixun_id').count
  end

  def get_valid_course_count(ids, end_time)
    percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < ?', end_time)
                       .select('sum(compelete_status >0 ) as finish, count(*) as total')
                       .having('total != 0 and finish >= (total / 2)').to_sql

    Course.joins(practice_homeworks: :homework_commons_shixun)
      .where('shixun_id in (?)', ids)
      .where("exists (#{percentage_sql})")
      .group('shixun_id').count
  end

  def get_valid_shixun_count(ids, end_time)
    percentage_sql = StudentWork.where('homework_common_id = homework_commons.id and homework_commons.publish_time is not null and homework_commons.publish_time < ?', end_time)
                       .select('sum(compelete_status >0 ) as finish, count(*) as total')
                       .having('total != 0 and finish >= (total / 2)').to_sql
    Shixun.joins(homework_commons_shixuns: :homework_common)
      .where(homework_commons: { homework_type: 4 })
      .where('course_id in (?)', ids)
      .where("exists (#{percentage_sql})")
      .group('course_id').count
  end
end
