<?php

/**
 * @author owen
 *
 */
class CrontabModel extends CI_Model{
    public $json = [];
    public $CDNInitDir    = ['image'];    // CDN初始化目录
    public $CDNMonitorDir = ['image'];    // CDN监听初始化目录
    public $CDNPath       = "http://god.superant.cc";    // CDN监听初始化目录

    /**
     * CDN资源初始化
     * Created by: Owen
     * Created on: 2021/3/13 18:10
     */
    public function initFileToCDN(){
        $pathSize = self::getFilePathAndSize($this->CDNInitDir);
        foreach ($pathSize as $path=>$size){
            oo::commonOprRedis('statistics')->hSet(okeys::MonitorCDNFile(),$path,$size);
        }
        echo "资源初始化成功";
    }

    public function monitorFileToCDN(){
        $len = oo::commonOprRedis('statistics')->hLen(okeys::MonitorCDNFile());
        if($len == 0){
            echo "资源未初始化";
            return;
        }
        if(count($this->CDNMonitorDir) > count($this->CDNInitDir)){
            echo "禁止存在监听未初始化的目录";
            return;
        }
        $pathSize = self::getFilePathAndSize($this->CDNMonitorDir);
        foreach ($pathSize as $path=>$size){
            if(empty($path)){
                continue;
            }
            $cache = oo::commonOprRedis('statistics')->hGet(okeys::MonitorCDNFile(),$path);
            $actionFlag = false;
            if(empty($cache)){
                $actionFlag = oo::commonOprModel('common')->CdnPushUrl($this->CDNPath.$path);
            }else if($cache != $size){
                $actionFlag = oo::commonOprModel('common')->CdnRefreshUrl($this->CDNPath.$path);
            }
            $actionFlag && oo::commonOprRedis('statistics')->hSet(okeys::MonitorCDNFile(),$path,$size);
        }
        echo "CDN 刷新成功";
        return;
    }

    public function getFilePathAndSize($dirArr){
        if(empty($dirArr)){
            return [];
        }
        foreach ($dirArr as $path){
            self::traverse(__ROOT__ ."/public/game/".$path);
        }
        return $this->json;
    }
    /**
     * 遍历应用根目录下的文件
     * @param $AppPath
     * @return bool|void
     * Created by: Owen
     * Created on: 2020/7/6 19:49
     */
    public function traverse($AppPath) {
        if (! file_exists ( $AppPath )) {
            printf ( $AppPath . " does not exist!" );
            return;
        }
        if (! is_dir ( $AppPath )) {
            printf ( $AppPath . " is not a directory!" );
            return;
        }
        if (! ($dh = opendir ( $AppPath ))) {
            printf ( "Failure while read diectory!" );
            return;
        }
        while ( ($file = readdir ( $dh )) != false ) {
            $subDir = $AppPath . DIRECTORY_SEPARATOR . $file;
            if ($file == "." || $file == "..") {
                continue;
            } else if (is_dir ( $subDir )) {
                self::traverse ( $subDir );
            } else {
                if (! file_exists ( $subDir )) {
                    return ;
                }
                $relativePath = str_replace ( __ROOT__, '', $subDir );
                $relativePath = str_replace ( "\\", "/", $relativePath );
                if (strpos ( $relativePath, "tmp/" ) === 0) {
                    return;
                }
                $this->json[$relativePath] = filesize($subDir);
            }
        }
        closedir ( $dh );
    }

    /**
     * https://www.tapd.cn/34348398/prong/stories/view/1134348398001001444
     * @param string $date
     * Created by: Owen
     * Created on: 2021/4/7 15:36
     */
    public function coinsValue($date = ""){
        if(empty($date)){
            $date = date("Ymd");
            $statisticsRedis = oo::commonOprRedis('statistics');
            $dauArr    = $statisticsRedis->hGetAll(okeys::CoinsValueSta("dau"));
            $tmpCoins = $statisticsRedis->hGetAll(okeys::CoinsValueSta("coins"));
            $totalCoins = [];
            foreach ($tmpCoins as $uid=>$row){
                $tmp = explode('-',$uid);
                $totalCoins[$tmp[1]] += $row;
            }
            $tmpSpins= $statisticsRedis->hGetAll(okeys::CoinsValueSta("spins"));
            $totalSpins = [];
            foreach ($tmpSpins as $uid=>$row){
                $tmp = explode('-',$uid);
                $totalSpins[$tmp[1]] += $row;
            }
            foreach ($totalSpins as $levelId=>$num){
                $spinValue[$levelId] = $num == 0 ? 0 : intval($totalCoins[$levelId]/$num);
            }
            $coinsAdd   = $statisticsRedis->hGetAll(okeys::CoinsValueSta("money+"));
            $coinsAddArr= [];
            foreach ($coinsAdd as $uid=>$num){
                $tmp = explode('-',$uid);
                $coinsAddArr[$tmp[0]] += intval($num/$spinValue[$tmp[1]]);
            }
            $coinsSpend= $statisticsRedis->hGetAll(okeys::CoinsValueSta("money-"));
            foreach ($coinsSpend as $uid=>$num){
                $tmp = explode('-',$uid);
                $coinsSpendArr[$tmp[0]] = intval($num/$spinValue[$tmp[1]]);
            }
            $spinsAddArr   = $statisticsRedis->hGetAll(okeys::CoinsValueSta("spins+"));
            $spinsSpendArr = $statisticsRedis->hGetAll(okeys::CoinsValueSta("spins-"));
            $slotNumArr    = $statisticsRedis->hGetAll(okeys::CoinsValueSta("slot"));
            $statisticsRedis->delete([okeys::CoinsValueSta("dau"), okeys::CoinsValueSta("coins"), okeys::CoinsValueSta("spins"), okeys::CoinsValueSta("money+"), okeys::CoinsValueSta("money-"), okeys::CoinsValueSta("spins+"), okeys::CoinsValueSta("spins-"), okeys::CoinsValueSta("slot")]);
        }else{
            $payWhiteList = array_filter(oo::commonOprModel("payment")->payWhiteList());
            $tmp = [];
            list($dauArr,$spinValue)  = $this->spinValue($date,$payWhiteList,$tmp);//体力价值
            $dauUidArr = array_keys($dauArr);
            list($coinsAddArr, $coinsSpendArr) = $this->coinOutInPut($date,$dauUidArr,$spinValue);
            list($spinsAddArr, $spinsSpendArr) = $this->spinOutInPut($date,$dauUidArr);
            $slotNumArr = $this->slotCount($date,$dauUidArr); // 9,10,11
        }
        $userCoinArr   = $this->UserCoin($dauArr,$spinValue); // 4,5,6
        $spinsStockArr = $this->UserSpin($dauArr); // 9,10,11

        $sqlValue = [];
        foreach ($spinValue as $levelId=>$value){
            $sqlValue[] = "('{$date}','{$levelId}','{$value}')";
        }
        if(!empty($sqlValue)){
            $sqlValue = implode(",",$sqlValue);
            $tb = otable::CoinsValueSta();
            oo::commonOprDb('statistics')->query("INSERT INTO {$tb}(`date`,`levelId`,`value`) VALUES {$sqlValue}");
        }
        $data = [];
        foreach ($dauArr as $uid=>$levelId){
            $value      = intval($spinValue[$levelId]);
            $coinsAdd   = intval($coinsAddArr[$uid]);
            $coinsSpend = intval($coinsSpendArr[$uid]);
            $coinsStock = intval($userCoinArr[$uid]);
            $spinsAdd   = intval($spinsAddArr[$uid]);
            $spinsSpend = intval($spinsSpendArr[$uid]);
            $spinsStock = intval($spinsStockArr[$uid]);
            $slotNum    = intval($slotNumArr[$uid]);
            $data[]  = "('{$date}','{$uid}','{$levelId}','{$value}','{$coinsAdd}','{$coinsSpend}','{$coinsStock}','{$spinsAdd}','{$spinsSpend}','{$spinsStock}','{$slotNum}')";
        }
        if(!empty($data)){
            $sqlValue = implode(",",$data);
            $tb = otable::ResourceMonitoringSta();
            oo::commonOprDb('statistics')->query("INSERT INTO {$tb}(`date`,`uid`,`levelId`,`coinsValue`,`coinsAdd`,`coinsSpend`,`coinsStock`,`spinsAdd`,`spinsSpend`,`spinsStock`,`slotNum`) VALUES {$sqlValue}");
        }
    }

    public function spinValue(&$date,&$payWhiteList,&$uidList){
        $spinValue  = [];
        $actionUid  = [];
        $database   = oo::commonOprModel('common')->getDbInstance(otable::Assetslog(),strtotime($date));
        $totalCoins = [];
        $totalSpins = [];
        for($i=0;$i<10;$i++){
            $tb  = otable::Assetslog($date,$i);
            $notStr = "";
            if(!empty($payWhiteList)){
                $actionWhiteList = [];
                foreach ($payWhiteList as $uid){
                    if($uid % 10 == $i){
                        $actionWhiteList[] = $uid;
                    }
                }
                if(!empty($actionWhiteList)){
                    $actionWhiteList = implode(",",$actionWhiteList);
                    $notStr = "AND uid NOT IN ({$actionWhiteList})";
                }
            }
            if(!empty($uidList)){
                $actionUidList = [];
                foreach ($uidList as $uid){
                    if($uid % 10 == $i){
                        $actionUidList[] = $uid;
                    }
                }
                if(!empty($actionUidList)){
                    $actionUidList = implode(",",$actionUidList);
                    $notStr = "AND uid IN ({$actionUidList})";
                }
            }
            $ret = oo::commonOprDb($database)->getAll("SELECT DISTINCT uid,levelId FROM {$tb} where `type`='spins' AND `crease`='-' AND `levelId` > 1 {$notStr} ORDER BY levelId DESC",MYSQLI_ASSOC);
            foreach ($ret as $row){
                $actionUid[$row['uid']] = $row["levelId"];
            }
            $uidArr    = array_column($ret,'uid');
            $inStr     = "";
            if(!empty($uidArr)){
                $uidStr = implode(',',$uidArr);
                $inStr  = "AND uid IN ({$uidStr})";
            }
            $coinArr = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,levelId FROM {$tb} where rid IN (1,2,3,4,9,10) AND `type`='money' AND `crease`='+' {$inStr} GROUP BY levelId",MYSQLI_ASSOC);
            $coinArr = array_column($coinArr,'num','levelId');
            foreach ($coinArr as $levelId=>$num){
                $totalCoins[$levelId] += intval($num);
            }
            $spinArr = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,levelId FROM {$tb} where rid=1 AND `type`='spins' AND `crease`='-' {$inStr} GROUP BY levelId",MYSQLI_ASSOC);
            $spinArr = array_column($spinArr,'num','levelId');
            foreach ($spinArr as $levelId=>$num){
                $totalSpins[$levelId] += intval($num);
            }
        }
        foreach ($totalSpins as $levelId=>$num){
            if($num > 0){
                $spinValue[$levelId] += intval($totalCoins[$levelId]/$num);
            }else {
                $spinValue[$levelId] += 0;
            }
        }
        return [
            $actionUid,
            $spinValue,
        ];
    }

    public function coinOutInPut(&$date,&$dauUidArr,&$spinValue,$only = 0,$ridList = []){
        $coinAddUidArr   = [];
        $coinSpendUidArr = [];
        $database   = oo::commonOprModel('common')->getDbInstance(otable::Assetslog(),strtotime($date));
        for($i=0;$i<10;$i++){
            $tb  = otable::Assetslog($date,$i);
            $actionDauUid = [];
            foreach ($dauUidArr as $uid){
                if($uid % 10 == $i){
                    $actionDauUid[] = $uid;
                }
            }
            $dauUidInStr = implode(",",$actionDauUid);
            $whereRid = "";
            if(!empty($ridList)){
                $ridList  = implode(",",$ridList);
                $whereRid = "AND rid IN ({$ridList})";
            }
            if($only != 2){
                $ret = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,uid,levelId FROM {$tb} where `type`='money' AND crease='+' AND uid IN ({$dauUidInStr}) {$whereRid} GROUP BY uid,levelId",MYSQLI_ASSOC);
                foreach ($ret as $row){
                    $coinAddUidArr[$row['uid']] += intval($row['num']/$spinValue[$row['levelId']]);
                }
            }
            if($only != 1){
                $ret = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,uid,levelId FROM {$tb} where `type`='money' AND crease='-' AND uid IN ({$dauUidInStr}) {$whereRid} GROUP BY uid,levelId",MYSQLI_ASSOC);
                foreach ($ret as $row){
                    $coinSpendUidArr[$row['uid']] += intval($row['num']/$spinValue[$row['levelId']]);
                }
            }
        }
        return [
            $coinAddUidArr,  //（金币产出=总金币获得/体力价值）
            $coinSpendUidArr //（金币消耗=总金币消耗/体力价值）
        ];
    }

    private function spinOutInPut(&$date,&$dauUidArr,$only = 0,$ridList = []){
        $spinAddUidArr   = [];
        $spinSpendUidArr = [];
        $database   = oo::commonOprModel('common')->getDbInstance(otable::Assetslog(),strtotime($date));
        for($i=0;$i<10;$i++){
            $tb  = otable::Assetslog($date,$i);
            $actionDauUid = [];
            foreach ($dauUidArr as $uid){
                if($uid % 10 == $i){
                    $actionDauUid[] = $uid;
                }
            }
            $whereRid = "";
            if(!empty($ridList)){
                $ridList  = implode(",",$ridList);
                $whereRid = "AND rid IN ({$ridList})";
            }
            $dauUidInStr = implode(",",$actionDauUid);
            if($only != 2){
                $ret = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,uid FROM {$tb} where `type`='spins' AND crease='+' AND uid IN ({$dauUidInStr}) {$whereRid} GROUP BY uid",MYSQLI_ASSOC);
                foreach ($ret as $row){
                    $spinAddUidArr[$row['uid']] = intval($row['num']);
                }
            }
            if($only != 1) {
                $ret = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,uid FROM {$tb} where `type`='spins' AND crease='-' AND uid IN ({$dauUidInStr}) {$whereRid} GROUP BY uid", MYSQLI_ASSOC);
                foreach ($ret as $row) {
                    $spinSpendUidArr[$row['uid']] = intval($row['num']);
                }
            }
        }
        return [
            $spinAddUidArr,
            $spinSpendUidArr
        ];
    }

    public function UserCoin(&$dauArr,&$spinValue){
        $userCoin = [];
        if(!empty($dauArr)){
            $tb  = otable::gh_gameserver();
            $dauUidArr   = array_keys($dauArr);
            $dauUidInStr = implode(",",$dauUidArr);
            $ret = oo::commonOprDb('slavedb')->getAll("SELECT money,mid FROM {$tb} where mid IN ({$dauUidInStr})",MYSQLI_ASSOC);
            $ret = array_column($ret,"money","mid");
            foreach ($ret as $uid=>$money){
                if($spinValue[$dauArr[$uid]] == 0){
                    $userCoin[$uid] = 0;
                }else{
                    $userCoin[$uid] = intval($money/($spinValue[$dauArr[$uid]]));
                }
            }
        }
        return $userCoin;//（金币存量=拥有金币/体力价值）
    }

    public function UserSpin(&$dauArr){
        $ret = [];
        if(!empty($dauArr)){
            $tb  = otable::gh_gameserver();
            $dauUidArr   = array_keys($dauArr);
            $dauUidInStr = implode(",",$dauUidArr);
            $ret = oo::commonOprDb('slavedb')->getAll("SELECT spins,mid FROM {$tb} where mid IN ({$dauUidInStr})",MYSQLI_ASSOC);
            $ret = array_column($ret,"spins","mid");
        }
        return $ret;
    }

    private function slotCount(&$date,&$dauArr){
        $slotCount  = [];
        $database   = oo::commonOprModel('common')->getDbInstance(otable::Assetslog(),strtotime($date));
        for($i=0;$i<10;$i++){
            $tb  = otable::Assetslog($date,$i);
            $uidArr = [];
            foreach ($dauArr as $uid){
                if($uid % 10 == $i){
                    $uidArr[] = $uid;
                }
            }
            $inStr     = "";
            if(!empty($uidArr)){
                $uidStr = implode(',',$uidArr);
                $inStr  = "AND uid IN ({$uidStr})";
            }

            $ret = oo::commonOprDb($database)->getAll("SELECT SUM(num) as num,uid FROM {$tb} where rid=1 AND `type`='spins' AND `crease`='-' {$inStr} GROUP BY uid",MYSQLI_ASSOC);
            foreach ($ret as $row){
                $slotCount[$row['uid']] = intval($row['num']);
            }
        }
        return $slotCount;
    }

    public function loginCountAndTime(){
        $ret  = oo::commonOprRedis('statistics')->hGetAll(okeys::LoginCount());
        $date = date("Ymd");
        $sqlValue = [];
        foreach ($ret as $uid=>$count){
            $time = oo::commonOprRedis('games')->hGet(okeys::LoginTime($uid),$uid); // 每日08分刪除記錄
            $sqlValue[] = "('{$date}','{$uid}','{$count}','{$time}')";
        }
        if(!empty($sqlValue)){
            $sqlValue = implode(",",$sqlValue);
            $tb = otable::UserLoginData();
            oo::commonOprDb('statistics')->query("INSERT INTO {$tb}(`date`,`uid`,`count`,`time`) VALUES {$sqlValue}");
        }
        oo::commonOprRedis('statistics')->delete(okeys::LoginCount());
    }

    public function pullLoginRegLog($date){
        set_time_limit(0);
        ini_set('memory_limit', -1);
        $dbConn = 'report';

        #创建注册日志表
        $regTble = otable::registerLog();
        $result = oo::commonOprModel('common')->createTable($regTble, $dbConn, 'registerLog');
        if($result){
            $this->pullRegLog($date, $dbConn);
        }

        #创建登录日志表
        $newLoginTbl = otable::newloginLog($date);
        $result = oo::commonOprModel('common')->createTable($newLoginTbl, $dbConn, 'newLoginLog');
        if($result){
            $this->pullLoginLog($date, $dbConn);
        }
    }

    private function pullLoginLog($date, $dbConn){
        $loginTbl = otable::LoginLog($date);
        $page = 0;
        $limit = 1000;

        $newLoginTbl = otable::newloginLog($date);
        $regTble = otable::registerLog();
        while(true){
            $page++;
            $offset = ( $page - 1 ) * $limit;
            $sql = "select uid,sid from {$loginTbl} group by uid, sid limit {$offset},{$limit}";
            $results = oo::commonOprDb('loginlog')->getAll($sql, 1);
            echo "page:{$page},cnt:".count($results) ;
            if(empty($results))break;
            $uids = array_map(function($v){ return $v['uid'];}, $results);
            $uidsStr = implode(',', $uids);
            $uidCountryMap = oo::commonOprDb($dbConn)->getAll("select * from {$regTble} where uid in ($uidsStr)", 1);
            $uidCountryMap = array_column($uidCountryMap, 'country', 'uid');
            $results = array_map(function($v) use($uidCountryMap){ return [$v['uid'], $v['sid'], $uidCountryMap[$v['uid']]];}, $results);
            $sql = Functions::db_intsertArrSQL($newLoginTbl, ['uid', 'sid','country'],  $results);
            oo::commonOprDb($dbConn)->query($sql, 1);
        }
    }
    private function pullRegLog($date, $dbConn){
        $stime = strtotime($date);
        $etime = $stime + 86400;
        $regTble = otable::registerLog();
        $userTbl = otable::userinfo();
        $addressTbl = otable::useraddress();
        $page = 0;
        $limit = 1000;
        while(true){
            $page++;
            $offset = ( $page - 1 ) * $limit;
            $sql = "select tu.uid,tu.createtime,ta.country_code from {$userTbl} tu inner join {$addressTbl} ta on tu.uid=ta.uid where createtime>={$stime} and createtime<={$etime} limit {$offset},{$limit}";
            $results = oo::commonOprDb('gameslave')->getAll($sql, 1);
            echo "page:{$page},cnt:".count($results);
            if(empty($results))break;
            $results = array_map(function($v){ return [$v['uid'], date('Ymd', $v['createtime']), $v['country_code']];}, $results);
            $sql = Functions::db_intsertArrSQL($regTble, ['uid', 'date', 'country'],  $results);
            oo::commonOprDb($dbConn)->query($sql, 1);
        }
    }

    public function foxRealTimeOnline($timestamp = 0){
        if(empty($timestamp))$timestamp = time();
        $start = $timestamp - 61;
        $onlineCnt = oo::commonOprRedis('games')->zCount(okeys::foxOnlineKey(),$start, $timestamp);
        echo $onlineCnt;
    }
}


?>