<?php

/**
 *	信鸽推送相关
 */

class PushModel extends CI_Model{
    public $pushTimeLimit = 0;

    public function __construct(){
        $this->pushTimeLimit = time() - 2*24*60*60;
    }

    /**
     *	通过UID获取推送的token
     */
    public function getPushTokenByUid($uid = 0){
        $table = otable::xg_push();
        $sql = "SELECT * FROM {$table} WHERE uid={$uid} LIMIT 1";
        $ret = oo::commonOprDb('slavedb')->getOne($sql, 1);
        if( empty($ret) ){
            return -1;
        }
        return $ret;
    }

    /**
     * 获取多个用户信息
     * @param array $uidList
     * @return array|bool
     * Created by: Owen
     * Created on: 2019/12/19 15:53
     */
    public function getPushMultByUids($uidList = array())
    {
        if(empty($uidList) || !is_array($uidList)){
            return false;
        }
        $uidStr = implode(',', $uidList);
        $table = otable::xg_push();
        $sql = " SELECT * FROM {$table} WHERE uid IN ({$uidStr}) ";
        $ret = oo::commonOprDb('slavedb')->getAll($sql, MYSQLI_ASSOC);
        if(empty($ret) ){
            return false;
        }
        $list = array();
        foreach ($ret as $value) {
            $list[] = [
                'uid'  => $value['uid'],
                'token'=> $value['token'],
                'lang' => $value['lang'],
                'topic'=> $value['topic'],
                'accountType'=> $value['accountType'],
                'sid'  => $value['sid'],
            ];
        }
        return $list;
    }

    public function actionPush($date,$time,$intervalTime,$title,$content,$userType,$type,$player,$deviceType,$accountType,$remark,$level,$userGroup,$arg = []){
        $tempTime    = $date.' '.$time;
        $table       = otable::PushSetting();
        $insertTitle = addslashes($title);
        $insertContent  = addslashes($content);
        $insertLevel    = is_array($level)?implode(',',$level):$level;
        $insertUserGroup= implode(',',$userGroup);
        $sql = " INSERT INTO {$table} (pn_content,pn_title,pn_time,pn_type,pn_player,pn_player_type,pn_devicetype,pn_accounttype,pn_remark,pn_level,pn_usergroup) VALUES('{$insertContent}', '{$insertTitle}', '{$tempTime}', '{$type}','{$player}',{$userType} ,{$deviceType} ,{$accountType},'{$remark}','{$insertLevel}','{$insertUserGroup}')";
        oo::commonOprDb('games')->query($sql);
        if($type == 0){
            //入库
            $table = otable::pushnews();
            $time = time();
            $sql = " INSERT INTO {$table} VALUES(NULL, '{$insertContent}', '{$insertTitle}', {$time}, '{$player}', 1)";
            oo::commonOprDb('games')->query($sql);
            $titleTmp = json_decode($title,true);
            if(!empty($titleTmp)){
                $title = $titleTmp;
            }
            $contentTmp = json_decode($content,true);
            if(!empty($contentTmp)){
                $content = $contentTmp;
            }
            if( $userType == 2 ){
                $uidArr = preg_split("/[\s,]+/", $player);
                self::pushNewsToMultUserLang($uidArr, $title, $content,$arg);
            }else{
                $actionSelect = false;
                $uidLimit = $this->getPushUserListByLastTime();
                if($level){
                    $uidLimit = $this->getPushUserListByLevelId($level[0],$level[1],$uidLimit);
                    $actionSelect = true;
                }
                if($userGroup){
                    $uidLimit = $this->getPushUserListByUserGroup($userGroup,$uidLimit);
                    $actionSelect = true;
                }
                if($actionSelect && empty($uidLimit)){
                    return true;
                }
                self::pushByTopicClassLang($deviceType, $accountType, $title, $content,$arg,$uidLimit);
            }
        }else{
            $sql = "SELECT max(id) AS id FROM {$table} WHERE 1";
            $ret = oo::commonOprDb('slavedb')->getOne($sql,1);
            $temp = json_encode([
                'time'        =>strtotime($tempTime),
                'intervalTime'=>$intervalTime,
                'type'        =>$type,
                'devicetype'  =>$deviceType,
                'accounttype' =>$accountType,
                'title'       =>$title,
                'content'     =>$content,
                'player'      =>$player,
                'usertype'    =>$userType,
                'arg'         =>$arg,
                'level'       =>$level,
                'userGroup'   =>$userGroup,
            ],JSON_NUMERIC_CHECK);
            oo::commonOprRedis('games')->hSet(okeys::PushNew(),$ret['id'],$temp);
        }
        return true;
    }

    /**
     * 推送入队
     * @param $token
     * @param $title
     * @param $content
     * @param $data
     * @param $sid
     * @return bool
     * Created by: Owen
     * Created on: 2020/3/23 16:18
     */
    public function push($token,$title,$content,$data = [],$sid = 1){
        return oo::commonOprRedis('games')->rpush(okeys::FireBaseList(),json_encode([
            'token'   => $token,
            'title'   => $title,
            'content' => $content,
            'data'    => $data,
            'sid'     => $sid,
            'label'   => "cms",
        ]));
    }

    /**
     * 推送出队
     * @param int $length
     * @return array
     * Created by: Owen
     * Created on: 2020/3/23 14:55
     */
    public function pop($length = 500){
        $key = okeys::FireBaseList();
        $ret  = oo::commonOprRedis('games')->lGetRange($key,0,$length);
        $return = [];
        foreach ($ret as $row){
            $return[] = json_decode($row,true);
        }
        oo::commonOprRedis('games')->lTrim($key,$length,-1);
        return $return;
    }

    /**
     * 定时推送
     * Created by: Owen
     * Created on: 2020/3/23 16:17
     */
    public function fireBasePushByRedisList(){
        $ret = self::pop();
        foreach ($ret as $row){
            try{
                oo::commonOprModel('firebase')->sendToDevice($row['token'], $row['title'], $row['content'], $row['data']??[]);
            }catch (Exception $exception){
                continue;
            }
        }
    }

    public function pushNewsToMultUserLang($uidList = array(), $title, $content,$arg = []){
        $count = count($uidList);
        $p = 100;
        $pages = ceil($count/$p);
        for ($i = 1; $i <= $pages; $i++) {
            $s = ($i-1)*$p;
            $tempArr = array_slice($uidList, $s , $p);
            $tokenList = self::getPushMultByUids($tempArr);
            if (!$tokenList) {
                continue;
            }
            foreach ($tokenList as $tokenArr) {
                if(isset($title[$tokenArr['lang']])){
                    $titleTemp = $title[$tokenArr['lang']];
                }else{
                    $titleTemp = $title['en'];
                }
                if(isset($content[$tokenArr['lang']])){
                    $contentTemp = $content[$tokenArr['lang']];
                }else{
                    $contentTemp = $content['en'];
                }
                self::push($tokenArr['token'], $titleTemp, $contentTemp,$arg,$tokenArr['sid']??1);
            }
        }
        return 1;
    }

    public function pushByTopicClassLang($deviceType, $accountType, $title, $content,$arg = [],$uidLimit = []){
        $sqlSid = "";
        if($deviceType){
            $sqlSid = "AND sid={$deviceType} ";
        }

        if(!empty($uidLimit)){
            $uidLimit = implode(',',$uidLimit);
            $sqlSid = "AND uid IN ({$uidLimit}) ";
        }

        $table = otable::xg_push();
        $firebaseTopic = okeys::FireBaseTopic();
        $time= time() - 2*24*60*60;
        $sql = "SELECT COUNT(uid) AS c FROM {$table} WHERE topic LIKE '%{$firebaseTopic}%' AND token != '0' {$sqlSid} AND updatetime > {$time}";
        if($accountType != 2){
            $sql .= " AND accountType={$accountType}";
        }
        $ret = oo::commonOprDb('slavedb')->getOne($sql, MYSQLI_ASSOC);
        $count = intval($ret['c']);
        if( $count <= 0 ){
            return;
        }
        $limit = 100;
        $pages = ceil($count / $limit);
        for ($i = 1; $i <= $pages; $i++) {
            $page = ($i -1) * $limit;
            $sqlList = "SELECT * FROM {$table} WHERE topic LIKE '%{$firebaseTopic}%' {$sqlSid} AND token != '0'  AND updatetime > {$time}";
            if($accountType != 2){
                $sqlList .= " AND accountType={$accountType}";
            }
            $sqlList .=" LIMIT {$page}, {$limit} ";
            $list = oo::commonOprDb('slavedb')->getAll($sqlList, MYSQLI_ASSOC);
            if(empty($list)) {
                continue;
            }
            $push = [];
            foreach ($list as $info) {
                $push[$info['lang']][] = ['token'=>$info['token'],'sid'=>$info['sid']];
            }
            foreach ($push as $key=>$row){
                if(isset($title[$key])){
                    $titleTemp = $title[$key];
                }else{
                    $titleTemp = $title['en'];
                }
                if(isset($content[$key])){
                    $contentTemp = $content[$key];
                }else{
                    $contentTemp = $content['en'];
                }
                foreach ($row as $t){
                    self::push($t['token'], $titleTemp, $contentTemp,$arg,$t['sid']);
                }
            }
        }
    }

    public function crontabPush(){
        $task = oo::commonOprRedis('games')->hGetAll(okeys::PushNew());
        if(empty($task)){
            var_dump('task is empty, run all');
            return;
        }

        if(!oo::commonOprRedis('games')->setnx(okeys::SinglePush(),1)){
            var_dump('task is running');
            return;
        }
        oo::commonOprRedis('games')->expire(okeys::SinglePush(),60*60);
        foreach ($task as $key=>$row){
            $temp = json_decode($row);
            $titleTmp = json_decode($temp->title,true);
            if(!empty($titleTmp)){
                $title = $titleTmp;
            }else{
                continue;
            }
            $contentTmp = json_decode($temp->content,true);
            if(!empty($contentTmp)){
                $content = $contentTmp;
            }else{
                continue;
            }
            if(time() < $temp->time){
                continue;
            }
            if( $temp->usertype == 2 ){
                $uidArr = preg_split("/[\s,]+/", $temp->player);
                self::pushNewsToMultUserLang($uidArr, $title, $content);
            }else{
                $actionSelect = false;
                $uidLimit = $this->getPushUserListByLastTime();
                if($temp->level){
                    $uidLimit = $this->getPushUserListByLevelId($temp->level[0],$temp->level[1],$uidLimit);
                    $actionSelect = true;
                }
                if($temp->userGroup){
                    $uidLimit = $this->getPushUserListByUserGroup($temp->userGroup,$uidLimit);
                    $actionSelect = true;
                }
                if(!($actionSelect && empty($uidLimit))){
                    //全服推送, 区分设备和账号类型
                    self::pushByTopicClassLang($temp->devicetype, $temp->accounttype, $title, $content,$temp->arg,$uidLimit);
                }
            }
            if($temp->type == 1){
                oo::commonOprRedis('games')->hDel(okeys::PushNew(),$key);
            }else if($temp->type == 2){
                $temp->time = time() + $temp->intervalTime * 60;
                oo::commonOprRedis('games')->hSet(okeys::PushNew(),$key,json_encode($temp));
            }
            $table = otable::pushnews();
            $time = time();
            $insertTitle   = addslashes($temp->title);
            $insertContent = addslashes($temp->content);
            $sql = " INSERT INTO {$table} VALUES(NULL, '{$insertContent}', '{$insertTitle}', {$time}, '{$temp->player}', 1)";
            oo::commonOprDb('games')->query($sql);
        }
        oo::commonOprRedis('games')->delete(okeys::SinglePush());
    }

    public function getPushUserListByLevelId($levelMin,$levelMax,$uidLimit = []){
        $tb    = otable::gh_gameserver();
        $where = "levelId>='{$levelMin}' AND levelId<='{$levelMax}'";
        if(!empty($uidLimit)){
            $uidLimit = implode(',',$uidLimit);
            $where .= " AND mid IN ({$uidLimit})";
        }
        $ret   = oo::commonOprDb('slavedb')->getAll("SELECT mid FROM {$tb} WHERE {$where}",MYSQLI_ASSOC);
        return array_column($ret,"mid");
    }

    public function getPushUserListByLastTime(){
        $tb    = otable::userinfo();
        $time  = $this->pushTimeLimit;
        $ret   = oo::commonOprDb('slavedb')->getAll("SELECT uid FROM {$tb} WHERE lasttime>'{$time}'",MYSQLI_ASSOC);
        return array_column($ret,"uid");
    }

    public function getPushUserListByUserGroup($groupIdArr,$uidLimit = []){
        if(empty($groupIdArr)){
            return [];
        }
        if(empty($uidLimit)){
            $uidLimit = $this->getPushUserListByLastTime();
        }
        $uidLimit = implode(',',$uidLimit);
        $where = "uid IN ({$uidLimit})";
        $groupIdWhere = [];
        foreach ($groupIdArr as $groupId){
            $groupIdWhere[] = "groupId2 LIKE '%{$groupId}%'";
        }
        $groupIdWhere = implode(' OR ',$groupIdWhere);
        $where .= " AND ({$groupIdWhere})";
        $tb    = otable::UserDynamicsData();
        $ret   = oo::commonOprDb('slavedb')->getAll("SELECT uid FROM {$tb} WHERE {$where}",MYSQLI_ASSOC);
        return array_column($ret,"uid");
    }
}
?>