<?php
/**
 *	排行榜相关
 */
class ModelRank
{
    protected $moneyRankLimit = 200; //世界排行榜
    protected $friMoneyRankLimit = 200; //好友排行榜人数限制
    protected $friNumLimit = 500; //好友人数限制
    protected $worldRankSum =1000;//最大世界排行
    protected $countryRankSum = 50;//最大国家排行
    protected $countryMaster =['RO','US','DE','GB','ES','FR','IN'];//主要国家：罗马尼亚，美国，德国，英国，西班牙，法国，印度，其他
    protected $rankMinStar = 2000; //正式服排行榜最小上榜值

    /**
     * Notes:获取排行榜信息
     * User: wsc
     * Time: 2020/5/6 19:26
     * @param $uid
     * @param bool $falg
     * @return array
     */
    public function getStaRank($uid,$falg=false){
        $my_friend_num = $my_country_num = 0;
        //好友榜
        $friendRankList = $this->getFriendRank($uid);

        //世界排行
        $friends = oo::commonOprModel('friend')->getUserAllFriend($uid);
        $worldRankList = $this->getWorldStaRank();
        foreach ($worldRankList as $k=>$v){
            $worldRankList[$k]['isFri'] =  in_array($v['uid'],$friends)?1:0;
        }

        //国家排行
        $countryList = $this->getCountryRank($uid);

        $myRank = $this->getMyRank($uid);
        foreach ($friendRankList as $k=>$v){
            if($v['uid']==$uid){
                $my_friend_num =  $k+1;
            }
        }
        $myRank['my_friend_rank'] = $my_friend_num;

        if(!empty($countryList)){
            foreach ($countryList as $k=>$v){
                if($v['uid']==$uid){
                    $my_country_num =  $k+1;
                }
            }
            $myRank['my_country_rank'] = $my_country_num<=$this->countryRankSum&&$my_country_num>0?$my_country_num:">".$this->countryRankSum;
            $countryList = array_values($countryList);
        }else{
            $countryList = [];
            $myRank['my_country_rank'] =0;
        }

        $myRank['max_worldRank'] = $this->worldRankSum;
        $myRank['max_countryRank'] = $this->countryRankSum;
        $data = [
            "code"=>1,
            "list"=>[
                "fir"=>$friendRankList,
                "world"=>array_values($worldRankList),
                "self"=>$myRank,
                "country"=>$countryList,
            ]
        ];

        oo::commonOprRedis('User')->setex(okeys::UserRankData($uid),json_encode([
            'friend'  => $myRank['my_friend_rank'],
            'country' => $myRank['my_country_rank'],
            'world'   => $myRank['pos'],
        ]),oo::redisRandomExpire(3*24*60*60));

        return $data;
    }

    /**
     * Notes:获取我的世界排名
     * User: wsc
     * Time: 2020/5/6 19:25
     * @param $uid
     * @return array
     */
    public function getMyRank($uid){
        $data = [];
        $info = oo::commonOprModel('member')->getUserBasic($uid);
        $stakey = okeys::worldStaRank();
        $res = oo::commonOprRedis('common')->zRevRank($stakey,$uid);
        $data['pos'] = $res?$res:">".$this->worldRankSum;
        $data['star'] = $info['star'];
        $data['nick'] = oo::commonOprModel('member')->getUserFirstName($info['nick']);
        $data['s_picture'] = $info['s_picture'];
        $data['u_flag'] = $info['u_flag'];
        return $data;
    }

    /**
     * Notes:获取我的好友排行榜
     * User: wsc
     * Time: 2020/5/6 19:25
     * @param $uid
     * @return array
     */
    public function getFriendRank($uid){
        $friends = oo::commonOprModel('friend')->getUserAllFriend($uid);
        $fbList  = oo::commonOprModel('friend')->getUserAllFriend($uid,'fb');
        array_push($friends,$uid);
        $friends = array_unique($friends);
        foreach ($friends as $k=>$v){
            $friendRankList[$k] = oo::commonOprModel('member')->getUserBasic($v);
            $infoArr = oo::commonOprModel('member')->getAccount($friendRankList[$k]['siteuid']);
            $friendRankList[$k]['isFb'] =!empty($infoArr) && $infoArr['uid'] == $v?1:0;
            unset($friendRankList[$k]['spins']);
            unset($friendRankList[$k]['shield']);
//            unset($friendRankList[$k]['coins']);
            unset($friendRankList[$k]['siteuid']);
            $friendRankList[$k]['isFbFriend'] =  in_array($v,$fbList)?1:0;
            $friendRankList[$k]['build'] =  oo::commonOprModel('member')->getUserLevel($v)['element'];
        }
        array_multisort(array_column($friendRankList,'star'),SORT_DESC,array_column($friendRankList,'money'),SORT_DESC,$friendRankList);
        $friendRankList =count($friendRankList)>$this->friMoneyRankLimit? array_slice($friendRankList,0,$this->friMoneyRankLimit):$friendRankList;
        return $friendRankList;
    }

    /**
     * Notes:获取世界排行（定时传参true刷新）
     * User: wsc
     * Time: 2020/5/6 19:24
     * @param bool $db
     * @return array
     */
    public function getWorldStaRank($db=false){
        $cache= [];
        $wkey = okeys::worldRankInfo();
        if(!$db){
            $jsonStr =oo::commonOprRedis('common')->hGetAll($wkey);
            $cache = funs::getArrFromJsonArr($jsonStr);
            array_multisort(array_column($cache,'star'),SORT_DESC,array_column($cache,'money'),SORT_DESC,$cache);
        }
        if(empty($cache)){
            oo::commonOprRedis('common')->delete($wkey);
            $rankList =  $this->newWorldStaRank($db);
            $i=0;
            foreach ($rankList as $k=>$v){
                $cache[$i] = $this->getUserSomeInfo($k);
                $data[$i] = json_encode($cache[$i]);
                $i++;
            }
            oo::commonOprRedis('common')->hMset($wkey,$data);
        }
        return $cache;
    }

    /**
     * Notes:更新世界排行
     * User: wsc
     * Time: 2020/5/20 19:49
     * @param bool $db
     * @return array
     */
    public function newWorldStaRank($db=false){
        $cache = [];
        $max  = oo::commonOprModel('readconfig')->getCon('Rank','maxNum');
        $stakey = okeys::worldStaRank();

        if(!$db){
            $cache =oo::commonOprRedis('common')->zRevRange($stakey,0,49,true);
        }
        if(empty($cache)){
            $tb   = otable::gh_gameserver(1);
            $sql  = "SELECT mid as uid,star FROM {$tb} ORDER BY star DESC,money DESC LIMIT {$this->worldRankSum}";
            $arr =  oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
            if(!empty($arr)){
                oo::commonOprRedis('common')->delete($stakey);
                foreach ($arr as $k=>$v){
                    oo::commonOprRedis('common')->zAdd($stakey,$v['star'],$v['uid']);
                    $cache[$v['uid']] = $v['star'];
                }
                $cache = array_slice($cache,0,50,true);
//                oo::logs()->debug3(["do"=>'update worldRank is success',"data"=>$cache],'worldRank.log');
            }
        }
        return $cache;
    }

    /**
     * Notes:获取个人国家排行榜
     * User: wsc
     * Time: 2020/5/20 19:59
     * @param $uid
     * @return array
     */
    public function getCountryRank($uid){
        $info =  oo::commonOprModel('ipaddress')->getUserCountry($uid);
        $ckey = okeys::countryRank($info['showCode']);
        $jsonStr =oo::commonOprRedis('common')->hGetAll($ckey);
        $cache = funs::getArrFromJsonArr($jsonStr);
        if(empty($cache)){
            return [];
        }
        array_multisort(array_column($cache,'star'),SORT_DESC,array_column($cache,'money'),SORT_DESC,$cache);
        return $cache;
    }

    /**
     * Notes:更新国家排行(新版)
     * User: richard
     * Time: 2021/3/30 18:29
     * @return array
     */
    public function newCountryRank(){
        $tb      = otable::useraddress();
        $tb2     = otable::gh_gameserver(1);
        $minStar = IS_DEBUF ? 500 : $this->rankMinStar; //最小星星上榜值
        $min     = 0;
        //设置主要国家排行
        foreach ($this->countryMaster as $country_code){
            $ckey      = okeys::countryRank($country_code);
            $tmp       = oo::commonOprRedis('common')->hGet($ckey, 49); //找到最后一名的数据
            if(empty($tmp)){ //如果没有50名排行，找最小的一个
                $tmpArr = oo::commonOprRedis('common')->hGetAll($ckey);
                krsort($tmpArr);
                $tmp = $tmpArr ? current($tmpArr) : [];
            }
            $lastRank  = $tmp ? (array)json_decode($tmp, true) : [];
            $star      = !empty($lastRank['star']) ? $lastRank['star'] : $this->rankMinStar;
            if(empty($min) || $min > $star){
                $min = $star;
            }
        }
        $ckey2    = okeys::countryRank("OTHER");
        $tmp      = oo::commonOprRedis('common')->hGet($ckey2, 49); //找到最后一名的数据
        $lastRank = $tmp ? (array)json_decode($tmp, true) : [];
        $star     = !empty($lastRank['star']) ? $lastRank['star'] : $this->rankMinStar;
        $min      = $min > $star ? $star : $min;
        $min      = empty($min) ? $minStar : $min;
        $sql      = "SELECT mid,star FROM {$tb2} WHERE star >= {$min} ORDER BY star DESC";
        $tmpList  = oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
        $rankUids = $tmpList ? array_column($tmpList, 'mid') : [];
        if(empty($rankUids)){
            return [[], []];
        }
        $cache = $data = [];
        foreach ($this->countryMaster as $country_code){
            $uidList = [];
            for($i = 0; $i < count($rankUids); $i=$i+5000){
                $tmpUids = array_slice($rankUids, $i, 5000);
                $uidStr  = implode(',', $tmpUids);
                $sql     = "SELECT uid FROM {$tb} WHERE country_code = '{$country_code}' AND uid IN({$uidStr})";
                $tmpUids = oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
                $uidList = array_merge($uidList, $tmpUids);
            }

            if(empty($uidList)){
                return [];
            }
            $ckey      = okeys::countryRank($country_code);
            $uids      = array_column($uidList, 'uid');
            oo::commonOprRedis('common')->delete($ckey);
            $index = 0;
            $cache = $data = [];
            foreach($rankUids as $uid){
                if(!in_array($uid, $uids)){
                    continue;
                }
                $cache[$index] = $this->getUserSomeInfo($uid);
                $data[$index] = json_encode($cache[$index]);
                $index++;
                if($index > 49){
                    break;
                }
            }
            oo::commonOprRedis('common')->hMset($ckey,$data);
        }
        //设置其他国家排行
        $masterStr = '"'.implode('","',$this->countryMaster).'"';
        $sql = "SELECT uid FROM {$tb} WHERE country_code NOT IN($masterStr) AND uid IN({$uidStr})";
        $uidList   = oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
        if(empty($uidList)){
            return [$data, []];
        }
        $uids = array_column($uidList, 'uid');
        oo::commonOprRedis('common')->delete($ckey2);
        $index = 0;
        $cache2 = $data2 = [];
        foreach($rankUids as $uid){
            if(!in_array($uid, $uids)){
                continue;
            }
            $cache2[$index] = $this->getUserSomeInfo($uid);
            $data2[$index] = json_encode($cache[$index]);
            $index++;
            if($index > 49){
                break;
            }
        }
        oo::commonOprRedis('common')->hMset($ckey2,$data2);
        return [$data,$data2];
    }

    /**
     * Notes:更新国家排行(旧版)
     * User: wsc
     * Time: 2020/5/20 19:59
     * @return array
     */
    public function newCountryRankOld(){
        $tb   = otable::useraddress();
        $tb2   = otable::gh_gameserver(1);
        //设置主要国家排行
        foreach ($this->countryMaster as $country_code){
            $sql = "SELECT a.uid,a.country_code,b.star FROM {$tb} a LEFT JOIN {$tb2} b ON a.uid=b.mid WHERE a.country_code='{$country_code}' order by b.star DESC LIMIT 50";
            $list =  oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
            $ckey = okeys::countryRank($country_code);
            if(!empty($list)){
                $i=0;
                oo::commonOprRedis('common')->delete($ckey);
                foreach ($list as $k=>$v){
                    $cache[$i] = $this->getUserSomeInfo($v['uid']);
                    $data[$i] = json_encode($cache[$i]);
                    $i++;
                }
                oo::commonOprRedis('common')->hMset($ckey,$data);
            }
        }
        //设置其他国家排行
        $masterStr = '"'.implode('","',$this->countryMaster).'"';
        $sql = "SELECT a.uid,a.country_code,b.star FROM {$tb} a LEFT JOIN {$tb2} b ON a.uid=b.mid WHERE a.country_code NOT IN({$masterStr}) ORDER BY b.star DESC LIMIT 50";
        $list2 =  oo::commonOprDb('common')->getAll($sql,MYSQLI_ASSOC);
        $ckey2 = okeys::countryRank("OTHER");
        $i=0;
        foreach ($list2 as $k=>$v){
            oo::commonOprRedis('common')->delete($ckey2);
            $cache[$i] = $this->getUserSomeInfo($v['uid']);
            $data2[$i] = json_encode($cache[$i]);
            $i++;
            oo::commonOprRedis('common')->hMset($ckey2,$data2);
        }
        return [$data,$data2];
    }

    public function getUserSomeInfo($uid){
        $cache = oo::commonOprModel('member')->getUserBasic($uid);
        $infoArr = oo::commonOprModel('member')->getAccount($cache['siteuid']);
        $cache['isFb'] =!empty($infoArr) && $infoArr['uid'] == $uid?1:0;
        $cache['fbId'] = $cache['siteuid'];
        $cache['build'] = oo::commonOprModel('member')->getUserLevel($uid)['element'];
        unset($cache['spins']);
        unset($cache['shield']);
//        unset($cache['coins']);
        unset($cache['siteuid']);
        return $cache;
    }

}
