<?php
/**
 * 排行榜
 * Created by PhpStorm.
 * User: guanxl
 * Date: 2018/3/27
 * Time: 9:13
 */

namespace App\Services;

use App\Models\User;
use App\Traits\Singleton;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class TopService
{
    use Singleton;
    const KNOWLEDGE_TOP = "bs_top:km";
    const JOIN_TOP = "bs_top:join";
    const JOIN_RATE_TOP = "bs_top:joinrate";
    const KM_AVG_TOP = "bs_top:kmavg";
    const PK_TOP = "bs_top:users:pk";
    const KM_TOP = "bs_top:users:km";
    const TOP_USERS = "bs_top:users";

    /**
     * @param $activityId
     */
    protected function cacheDepartmentTop($activityId){

        $datas = DB::select("select count(*) as user_num,sum(is_blockade_success_copy) as sum_is_blockade_success,sum(knowledge_money)as sum_knowledge_money,department_id,avg(knowledge_money) as avg_knowledge_money from bs_users where department_id>0 and status=1 and activity_id={$activityId} 
GROUP BY department_id");

        foreach ($datas as $data){
            $joinRate = 0;
            if($data->user_num>0){
                $joinRate = ($data->sum_is_blockade_success/$data->user_num)*100;
            }
            Redis::zAdd(self::KNOWLEDGE_TOP.":".$activityId,$data->sum_knowledge_money,$data->department_id);
            Redis::zAdd(self::JOIN_TOP.":".$activityId,$data->sum_is_blockade_success,$data->department_id);
            Redis::zAdd(self::JOIN_RATE_TOP.":".$activityId,$joinRate,$data->department_id);
            Redis::zAdd(self::KM_AVG_TOP.":".$activityId,$data->avg_knowledge_money,$data->department_id);
        }

        Redis::expire(self::KNOWLEDGE_TOP.":".$activityId,300);
        Redis::expire(self::JOIN_RATE_TOP.":".$activityId,300);
        Redis::expire(self::JOIN_TOP.":".$activityId,300);
        Redis::expire(self::KM_AVG_TOP.":".$activityId,300);

    }

    /**
     * 个人知识币全行排行榜信息
     * @param $activityId
     * @param string $limit
     * @return mixed
     */
    public function personKmTop($activityId,$limit = "")
    {
       return $this->getKmTop($activityId,$limit);
    }

    /**
     * 得到用户在全行的排名
     * @param $activityId
     * @param $userId
     * @return mixed
     */
    public function personKmRank($activityId,$userId)
    {
        return $this->getKmRank($activityId,$userId);
    }

    /**
     * 所有用户在全行的PK排名
     * @param $activityId
     * @param string $limit
     * @return mixed
     */
    public function personPktop($activityId,$limit=""){
        return $this->getPkTop($activityId,$limit);
    }

    /**
     * 当前用户在全行的排名
     * @param $activityId
     * @param $userId
     * @return int
     */
    public function personPkRank($activityId,$userId)
    {
        return $this->getPkRank($activityId,$userId);
    }

    /**
     * 现在1000名的知识币
     * 可以获得奖项的知识币
     * @param $activityId
     * @param int $rank
     * @return int
     */
    public function prizeKmRank($activityId,$rank = 1000)
    {
        $users = User::where("activity_id",$activityId)->where("status",1)
                                                        ->where("is_blockade_success",1)
                                                        ->orderBy("knowledge_money","desc")
                                                        ->pluck("knowledge_money","user_id");
        $users = collect($users)->toArray();
        $i=0;
        foreach ($users as $key=>$knowledgeMoney){
            $i++;
            if($i==$rank){
                return $knowledgeMoney;
            }
        }
        return 0;
    }

    /**
     * 个人知识币分行排行榜信息
     * @param $activityId
     * @param $departmentId
     * @param string $limit
     * @return mixed
     */
    public function personKmDepartmentTop($activityId,$departmentId,$limit = "")
    {

        $userIds = DepartmentService::getInstance()->getUserIdsByDepartmentId($departmentId);
        $users = [];
        if($userIds){
            $users = $this->getUsers($activityId,collect($userIds)->toArray());
        }
        if($limit>0){
            $users = collect($users)->sortByDesc("knowledge_money")->values()->take($limit);
        }else{
            $users = collect($users)->sortByDesc("knowledge_money")->values()->all();
        }

        return $users;

    }


    /**
     * 得到用户在分行的排名
     * @param $activityId
     * @param $userId
     * @param $departmentId
     * @return mixed
     */
    public function personKmDepartmentRank($activityId,$userId, $departmentId)
    {
        $userIds = DepartmentService::getInstance()->getUserIdsByDepartmentId($departmentId);
        $users = [];
        if($userIds){
            $users = $this->getUsers($activityId,collect($userIds)->toArray());
        }
        $users = collect($users)->sortByDesc("knowledge_money")->values()->all();
        $i=0;
        foreach ($users as $user){
            $i++;
            if($user["user_id"]==$userId){
                return $i;
            }
        }
    }

    /**
     * 获取所有分行员工完成必答排行
     * @param $activityId
     * @param string $limit
     * @return mixed
     */
    public function departmentJoinTop($activityId,$limit = "")
    {
        $redisKey = self::JOIN_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }
        $options = array('withscores' => true);
        if ($limit) {
            $options["limit"] = $limit;
        }
        return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
    }

    /**
     * 获取所有分行的总知识币
     * @param $activityId
     * @param string $limit
     * @return mixed
     */
    public function departmentKmTop($activityId,$limit="")
    {
        $redisKey = self::KNOWLEDGE_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }
        $options = array('withscores' => true);
        if ($limit) {
            $options["limit"] = $limit;
        }
        return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
    }

    /**
     * 获取分行参与率的排行榜
     * @param $activityId
     * @param string $limit
     * @return
     */
    public function departmentJoinRateTop($activityId,$limit = "")
    {
        $redisKey = self::JOIN_RATE_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }
        $options = array('withscores' => true);
        if ($limit) {
            $options["limit"] = $limit;
        }
        return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
    }

    /**
     * 获取分行平均分排行榜
     * @param $limit
     * @return mixed
     */
    public function departmentKmAvgTop($activityId,$limit = "")
    {
        $redisKey = self::KM_AVG_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }
        $options = array('withscores' => true);
        if ($limit) {
            $options["limit"] = $limit;
        }
        return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
    }

    /**
     * 某分行的排名
     * @param $activityId
     * @param $departmentId
     * @return array
     */
    public function departmentJoinRateRank($activityId,$departmentId)
    {
        $redisKey = self::JOIN_RATE_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }

        $rank = Redis::zRevrank($redisKey, $departmentId);
        if (is_null($rank)) {
            return ["index" => 0, "rate" => 0];
        } else {
            $rate = Redis::zScore($redisKey, $departmentId);
            return ["index" => $rank + 1, "rate" => $rate];
        }
    }

    /**
     * 某分行的排名
     * @param $departmentId
     * @return array
     */
    public function departmentKmAvgRank($activityId,$departmentId)
    {
        $redisKey = self::KM_AVG_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $this->cacheDepartmentTop($activityId);
        }

        $rank = Redis::zRevrank($redisKey, $departmentId);
        if (is_null($rank)) {
            return ["index" => 0, "avg_knowledge_money" => 0];
        } else {
            $avgKm = Redis::zScore($redisKey, $departmentId);
            return ["index" => $rank + 1, "avg_knowledge_money" => round($avgKm,2)];
        }
    }

    /**
     * 获得用户排行信息
     * @param $activityId
     * @param array $userIds
     * @return array
     */
    public function getUsers($activityId,$userIds=[]){
        $redisKey = self::TOP_USERS.":".$activityId;
        if(!Redis::exists($redisKey)){
            $departments = DepartmentService::getInstance()->all($activityId);
            $pagesize = 5000;
            $count = User::where("activity_id",$activityId)->where("status",1)->count();
            $pageCount = ceil($count/$pagesize);
            for ($page=0;$page<$pageCount;$page++){
                $users = User::where("activity_id",$activityId)->where("status",1)->offset($page*$pagesize)->limit($pagesize)->get([
                    "user_id","name","avatar","department_id","knowledge_money","user_level","user_star"
                ]);

                $redisData = [];
                foreach ($users as $user){
                    $user = collect($user)->toArray();
                    $user["department_name"] = empty($departments[$user["department_id"]])? "":$departments[$user["department_id"]];
                    $redisData[$user["user_id"]] = json_encode($user,256);
                }
                if($redisData){
                    Redis::hmset($redisKey,$redisData);
                }
            }
            Redis::expire($redisKey,864000);
        }
        if(empty($userIds)){
            $users = Redis::hgetall($redisKey);
        }else{
            $users = Redis::hmget($redisKey,$userIds);
        }
        $datas = [];
        foreach ($users as $key=>$val){
            $datas[$key] = json_decode($val,true);
        }
        return $datas;
    }


    /**
     * 更新用户的排名信息
     * @param $userId
     * @return mixed
     */

    public function updateUserTop($userId){
        $user = UserService::getInstance()->getUser($userId,"",true);
        if($user){
            $activityId = $user["activity_id"];
            $redisData = [
                "user_id" => $userId,
                "name" => $user["name"],
                "avatar" => $user["avatar"],
                "department_id" => $user["department_id"],
                "department_name" => DepartmentService::getInstance()->getDepartmentName($user["department_id"]),
                "knowledge_money" => $user["knowledge_money"],
                "user_level" => $user["user_level"],
                "user_star" => $user["user_star"]
            ];
            if(Redis::exists(self::TOP_USERS . ":".$activityId)) {
                Redis::hset(self::TOP_USERS . ":" . $activityId, $userId, json_encode($redisData, 256));
            }
            if(Redis::exists(self::KM_TOP . ":".$activityId)){
                Redis::zadd(self::KM_TOP . ":".$activityId,$user["knowledge_money"],$userId);
            }
            if(Redis::exists(self::PK_TOP . ":".$activityId)) {
                Redis::zadd(self::PK_TOP . ":" . $activityId, $user["user_level"] * 1000 + $user["user_star"], $userId);
            }
            return true;
        }
        return false;
    }


    /**
     * 取用户的km段位排名
     * @param $activityId
     * @param $userId
     * @return int
     */
    public function getKmRank($activityId,$userId){
        $redisKey = self::KM_TOP . ":".$activityId;
        $this->getKmTop($activityId,1);
        $rank = Redis::zRevrank($redisKey, $userId);
        if (is_null($rank)) {
            return 0;
        } else {
            return $rank + 1;
        }
    }


    /**
     * 取用户的PK段位排名
     * @param $activityId
     * @param $userId
     * @return int
     */
    public function getPkRank($activityId,$userId){
        $redisKey = self::PK_TOP . ":".$activityId;
        $this->getPkTop($activityId,1);
        $rank = Redis::zRevrank($redisKey, $userId);
        if (is_null($rank)) {
            return 0;
        } else {
            return $rank + 1;
        }
    }

    /**
     * PK段位排行榜
     * @param $activityId
     * @param int $limit
     * @return mixed
     */
    public function getPkTop($activityId,$limit=100){
        $redisKey = self::PK_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $users = $this->getUsers($activityId);
            foreach ($users as $key=>$val){
                Redis::zadd($redisKey,$val["user_level"]*1000+$val["user_star"],$key);
            }
            Redis::expire($redisKey,84600);
        }

        $options = [];
        if ($limit) {
            $options["limit"] = [0,$limit];
        }
        $datas = [];
        $userIds =  Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
        if($userIds){
            $datas = $this->getUsers($activityId,$userIds);
        }
        return $datas;
    }

    /**
     * 知识币排行
     * @param $activityId
     * @param int $limit
     * @return mixed
     */
    public function getKmTop($activityId,$limit=100){
        $redisKey = self::KM_TOP . ":".$activityId;
        if(!Redis::exists($redisKey)){
            $users = $this->getUsers($activityId);
            foreach ($users as $key=>$val){
                Redis::zadd($redisKey,$val["knowledge_money"],$key);
            }
            Redis::expire($redisKey,84600);
        }

        $options = [];
        if ($limit) {
            $options["limit"] = [0,$limit];
        }
        $userIds =  Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
        $datas = [];
        if($userIds){
            $datas = $this->getUsers($activityId,$userIds);
        }
        return $datas;
    }
}