<?php
/**

 */
namespace common\helpers\bonus;

use common\helpers\Cache;
use common\helpers\Date;
use common\helpers\snowflake\SnowFake;
use common\models\PerfOrder;
use common\models\PerfPeriod;
use common\models\Period;
use common\models\PerfMonth;
use common\models\ServeLog;
use common\models\User;
use common\models\UserNetwork;
use yii\base\Exception;
use yii\base\StaticInstanceTrait;

class CalcServePerfCalc {
    use StaticInstanceTrait;

    private $_limit = 3000;
    private $_companyMonthPerf = 0;
    private $_cfTotalPercent = 0;
    private $_lxTotalPercent = 0;
    private $_sysConfig = [];
    private $_decLevelConfig = [];
    private $_empLevelConfig = [];
    private $_decRoleConfig = [];
    private $_periodNum = 0;
    private $_isCalcMonth = 0;
    private $_calcYear;
    private $_calcMonth;
    private $_calcYearMonth;
    private $_lastCalcYear;
    private $_lastCalcMonth;
    private $_lastCalcYearMonth;
    private $_lastPeriodNum;
    private $_periodObj;

    const LOOP_FINISH = 1;
    const LOOP_CONTINUE = 2;

    const ORDER_PAY_TYPE_CASH = 'cash';
    const ORDER_PAY_TYPE_STACK = 'pay_stack'; // pay_stack支付方式

    /**
     * 获取期数
     * @return int
     */
    public function getPeriodNum() {
        return $this->_periodNum;
    }

    // 校验是否可进行计算
    public function isCalcIng($periodNum) {
        $periodObj = Period::instance();
        $periodDataArr = $periodObj->setPeriodNum($periodNum);
        if (empty($periodDataArr)) {
            return false;
        }
        if ($periodDataArr['IS_PREPARE'] != 1) {
            return false;
        }
        $this->_periodNum = $periodDataArr['PERIOD_NUM'];
        $this->_periodObj = $periodObj;

        return true;
    }

    /**
     * 累计业绩数据
     * @param $periodNum
     * @return bool
     */
    public function calcStep($periodNum = null) {
        try {
            //一、查询此业绩状态,是否能进行计算
            $calcIng = $this->isCalcIng($periodNum);
            if ($calcIng !== true) {
                return false;
            } else {
                // 将IS_PREPARE改成2,计算中
                Period::updateCalcProcess(2, $this->_periodNum);
            }

            $this->initCalcTask();

            // 日志----记录开始,业绩期,结算年月
            ServeLog::periodMonth($this->_periodNum, $this->_calcYearMonth);

            // 日志----记录推送过来的基础数据
            ServeLog::basicData($this->_periodNum, $this->_calcYearMonth);

            $t1 = microtime(true);
            //二、初始化
            echo '业绩期为：'.$this->_periodNum;
            Period::updatePercent(10, $this->_periodNum);
            
            //三、 设置结算状态
            $this->setCalcStatus('start', $this->_periodNum);
            
            //四、 清空所有本期结算用到的缓存
            CalcCache::clearAll($this->_periodNum);

            //五、 清空会员推荐和接点关系缓存
            CalcCache::clearNetCache();

            //六、 清空相关表数据
            // 日志----清除业绩表
            ServeLog::clearPerf($this->_periodNum, $this->_calcYearMonth);
            $this->clearTableData();
            $this->_updatePercent(15);

            $t2 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'初始化、清空缓存及相关数据表完成，耗时：' . round($t2 - $t1, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            
            //七、 添加缓存中用户数据
            // 日志----开始缓存用户
            ServeLog::noParamsLog($this->_periodNum, $this->_calcYearMonth, '缓存用户信息-开始', 400);
            CalcCache::addUsers($this->_periodNum);
            // 日志----缓存用户结束
            ServeLog::cacheUserTotal($this->_periodNum, $this->_calcYearMonth);

            $t3 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'计算业绩向缓存中加入用户完成，耗时：' . round($t3 - $t2, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            $this->_updatePercent(20);

            // 八、循环累计用户各项业绩数据
            $this->loopGrandPerf();
            $t4 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'累计用户业绩完成' . round($t4 - $t3, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            $this->_updatePercent(60);
            
            // 九、本期业绩入库
            $this->loopWriteNowPerf();
            $t6 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'本期业绩入库完成，耗时：' . round($t6 - $t4, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            //日志----记录期业绩数据
            ServeLog::perfPeriodInfo($this->_periodNum, $this->_calcYearMonth);
            $this->_updatePercent(70);

            //十、计算月业绩表中的数据
            $this->loopCalcMonthPerfTableData();
            $t7 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'计算月业绩表中的数据完成，耗时：' . round($t7 - $t6, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            $this->_updatePercent(80);

            //十一、本月业绩入库
            $this->loopWriteMonthPerf();
            $t8 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'本月业绩入库完成，耗时：' . round($t8 - $t7, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            //日志----记录月期业绩数据
            ServeLog::perfMonthInfo($this->_periodNum, $this->_calcYearMonth);
            $this->_updatePercent(90);
            

            //十二、期业绩表，增加是否活跃字段
            $this->loopUpdatePeriodActive();
            $t9 = microtime(true);
            echo(date('Y-m-d H:i:s',time()).'期业绩表活跃状态更新完成，耗时：' . round($t9 - $t8, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            $this->_updatePercent(100);
            //日志----记录期业绩表活跃多少人
            ServeLog::perfPeriodActive($this->_periodNum, $this->_calcYearMonth);
            echo(date('Y-m-d H:i:s',time()).'计算业绩业绩结算全部完成，共耗时：' . round($t9 - $t1, 3) . ',内存使用：' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
            ServeLog::noParamsLog($this->_periodNum, $this->_calcYearMonth, '业绩计算完毕', 900);
        } catch (\Exception $e) {
            $this->errorCalcTask();
            var_dump($e->getMessage());
            return false;
        }

        $this->endCalcTask();

        return true;
    }

    /**
     * 结算完成
     * @return bool
     */
    public function endCalcTask() {
        // 更新结算状态
        $this->setCalcStatus('end');
    }

    /**
     * 结算错误
     */
    public function errorCalcTask() {
        // 清空所有本期结算用到的缓存
        CalcCache::clearAll($this->_periodNum);
        // 更新结算状态
        $this->setCalcStatus('fail');
    }

    /**
     * 设置生成业绩单状态
     * @param $type
     * start|end|fail
     */
    public function setCalcStatus($type, $periodNum = null) {
        if ($type == 'start') {
            Period::updateAll(['IS_PERFING' => 1, 'IS_PERFED' => Period::PERF_NONE, 'PERF_STARTED_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
        } elseif ($type == 'end') {
            Period::updateAll(['IS_PERFING' => 0, 'IS_PERFED' => Period::PERF_FINISH, 'PERFED_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
        } elseif ($type == 'fail') {
            Period::updateAll(['IS_PERFING' => 0, 'IS_PERFED' => Period::PERF_FAIL, 'PERFED_AT' => 0], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
        }
    }

    /**
     * 初始化结算任务
     * @throws \yii\db\Exception
     */
    public function initCalcTask() {
        try {
            $periodObj = Period::instance();
            $this->_sysConfig = Cache::getSystemConfig();
            $this->_decLevelConfig = Cache::getDecLevelConfig();
            $this->_empLevelConfig = Cache::getEmpLevelConfig();
            $this->_decRoleConfig = CalcCache::getDecRoleConfig($this->_periodNum);
            $this->_isCalcMonth = $periodObj->isCalcMonth($this->_periodNum);
            $this->_calcYear = $periodObj->getYear($this->_periodNum);
            $this->_calcMonth = $periodObj->getMonth($this->_periodNum);
            $this->_calcYearMonth = $periodObj->getYearMonth($this->_periodNum);
        } catch(Exception $e) {
            var_dump($e->getMessage());
        }
    }

    /**
     * 清空相关表数据
     */
    public function clearTableData() {
        PerfPeriod::pageDeleteAll('PERIOD_NUM='.$this->_periodNum);// 周业绩
        if ($this->_isCalcMonth) {
            PerfMonth::pageDeleteAll("CALC_MONTH='{$this->_calcYearMonth}'");// 月业绩表
        }
    }

    /**
     * 累计用户业绩
     * @param int $offset
     * @return bool
     * @throws \yii\db\Exception
     */
    public function loopGrandPerf($offset = 0) {
        $allData = PerfOrder::findUseDbCalc()
        ->select('ORDER_AMOUNT,DEC_TYPE,USER_ID,PV,PERIOD_NUM,DEC_USER_ID,PAY_TYPE')
        ->where(
            "PERIOD_NUM=:PERIOD_NUM", 
            [':PERIOD_NUM' => $this->_periodNum]
        )
        ->orderBy('CREATED_AT DESC,ID DESC')
        ->offset($offset)
        ->limit($this->_limit)
        ->asArray()
        ->all();
        if (!empty($allData)) {
            foreach ($allData as $data) {
                // 循环累计报单业绩
                try{
                    echo "开始累计用户业绩，用户ID为：".$data['USER_ID'].PHP_EOL;
                    if ($data['DEC_TYPE'] == PerfOrder::ZC_TYPE) {
                        // 给自己增加PCS(个人消费)
                        CalcCache::nowPeriodPerf($data['USER_ID'], $this->_periodNum, [
                            'PV_PCS' => $data['PV'],
                            'PV_PCS_ZC' => $data['PV'],
                        ]);
                        // 把该会员加入到能拿到业绩的会员缓存中
                        CalcCache::addHasPerfUsers($data['USER_ID'], $this->_periodNum);
                        //加入到报单会员中
                        $toInfo = CalcCache::getUserInfo($data['USER_ID'], $this->_periodNum);
                        CalcCache::addHasBDUsers($data['USER_ID'], $this->_periodNum, [
                            'TO_USER_ID' => $data['USER_ID'],
                            'USER_ID' => $toInfo['DEC_ID'],
                            'DEC_ID' => $toInfo['DEC_ID'],
                            //考虑可能会移网的情况
                            'REC_USER_ID' => $toInfo['REC_UID'] ?? '',
                            'CON_USER_ID' => $toInfo['CON_UID'] ?? '',
                            'DEC_AMOUNT' => $data['ORDER_AMOUNT'],
                            'DEC_PV' => $data['PV'],
                        ]);
                        // 给上追加业绩
                        $this->loopNetworkParentDo($data['USER_ID'], function ($parent) use (&$data) {
                            // 给上级会员追加本期业绩到缓存中
                            CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
                                'PV_' . $parent['LOCATION'] . 'L' => $data['PV'],
                                'PV_' . $parent['LOCATION'] . 'L_TOUCH' => $data['PV'],
                                'PV_' . $parent['LOCATION'] . 'L_' . $data['DEC_TYPE'] => $data['PV'],
                            ]);
                            // 把该会员加入到能拿到业绩的会员缓存中
                            CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
                            unset($parent);
                        });
                        //给推荐关系累计增加业绩
                        $this->loopRelationParentDo($data['USER_ID'], function ($parent) use (&$data) {
                            // 给上级会员追加本期业绩到缓存中
                            CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
                                'PV_PSS' => $data['PV'],
                            ]);
                            // 把该会员加入到能拿到业绩的会员缓存中
                            CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
                            unset($parent);
                        });
                    }
                } catch(Exception $e) {
                    var_dump(__LINE__,__FILE__,$e->getMessage(), $data);
                }
                
                // 循环累计复消业绩
                try{
                    if ($data['DEC_TYPE'] == PerfOrder::FX_TYPE) {
                        if( $data['PAY_TYPE'] === self::ORDER_PAY_TYPE_CASH || $data['PAY_TYPE'] === self::ORDER_PAY_TYPE_STACK) {
                            $orderCashAmount = $data['ORDER_AMOUNT'];
                            $payPv = $data['PV'] * $this->_sysConfig['cashReconsumeBonusPercent']['VALUE'] / 100;
                            $cacheDataKey = 'PV_PCS_FX_CASH';
                        } else {
                            $orderCashAmount = 0;
                            $payPv = $data['PV'];
                            $cacheDataKey = 'PV_PCS_FX_POINT';
                        }

                        if( $payPv <= 0 ) continue;
                        // 给自己增加PCS(个人消费)
                        CalcCache::nowPeriodPerf($data['USER_ID'], $this->_periodNum, [
                            'FX_AMOUNT_CASH' => $orderCashAmount,
                            'PV_PCS' => $payPv,
                            'PV_PCS_FX' => $payPv,
                            $cacheDataKey => $payPv,
                        ]);
                        // 把该会员加入到能拿到业绩的会员缓存中
                        CalcCache::addHasPerfUsers($data['USER_ID'], $this->_periodNum);
                        // 给上追加业绩
                        $this->loopNetworkParentDo($data['USER_ID'], function ($parent) use (&$data, $payPv) {
                            // 给上级会员追加本期业绩到缓存中
                            CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
                                'PV_' . $parent['LOCATION'] . 'L' => $payPv,
                                'PV_' . $parent['LOCATION'] . 'L_TOUCH' => $payPv,
                                'PV_' . $parent['LOCATION'] . 'L_FX' => $payPv,
                            ]);
                            // 把该会员加入到能拿到业绩的会员缓存中
                            CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
                        });
                        //给推荐关系累计增加业绩
                        $this->loopRelationParentDo($data['USER_ID'], function ($parent) use ($data, $payPv) {
                            // 给上级会员追加本期业绩到缓存中
                            CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
                                'PV_PSS' => $payPv,
                            ]);
                            // 把该会员加入到能拿到业绩的会员缓存中
                            CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
                        });
                    }
                }catch(Exception $e) {
                    var_dump(__LINE__,__FILE__,$e->getMessage(), $data);
                }
            }

            return $this->loopGrandPerf($offset + $this->_limit);
        }
        unset($allData);
        return true;
    }

    /**
     * 计算月业绩表相关的数据并写入数据库
     * @param int $offset
     * @return bool
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public function loopCalcMonthPerfTableData(int $offset = 0) {
        if (!$this->_isCalcMonth) {
            return true;
        }
        echo sprintf("时间:[%s]月业绩，当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
        $allData = PerfPeriod::findUseDbCalc()
        ->select('USER_ID, SUM(FX_AMOUNT_CASH) AS FX_AMOUNT_CASH_SUM,SUM(PV_PCS) AS PV_PCS_SUM,SUM(PV_PCS_FX) AS PV_PCS_FX_SUM,
        SUM(PV_PSS) AS PV_PSS_SUM,SUM(PV_1L) AS PV_1L_SUM,SUM(PV_2L) AS PV_2L_SUM,SUM(PV_3L) AS PV_3L_SUM,
        SUM(PV_4L) AS PV_4L_SUM,SUM(PV_5L) AS PV_5L_SUM,SUM(PV_1L_ZC) AS PV_1L_ZC_SUM,SUM(PV_2L_ZC) AS PV_2L_ZC_SUM,
        SUM(PV_3L_ZC) AS PV_3L_ZC_SUM,SUM(PV_4L_ZC) AS PV_4L_ZC_SUM,SUM(PV_5L_ZC) AS PV_5L_ZC_SUM')
        ->where('CALC_MONTH=:CALC_MONTH', [':CALC_MONTH' => $this->_calcYearMonth])
        ->groupBy('USER_ID')
        ->orderBy('USER_ID DESC')
        ->offset($offset)
        ->limit($this->_limit)
        ->asArray()
        ->all();
        if ($allData) {
            // 月度业绩表
            foreach ($allData as $everyData) {
                $userId = $everyData['USER_ID'];
                //往期业绩
                $userLastPerf = CalcCache::userPerf($userId, $this->_periodNum);
                //本期业绩
                $periodPerf = CalcCache::nowPeriodPerf($userId, $this->_periodNum);
                $userBaseInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
                $nowMonthPerf = [
                    'USER_ID' => $userId,
                    'FX_AMOUNT_CASH' => $everyData['FX_AMOUNT_CASH_SUM'],
                    'PV_PCS' => $everyData['PV_PCS_SUM'],
                    'PV_PCS_FX' => $everyData['PV_PCS_FX_SUM'],
                    'PV_PSS' => $everyData['PV_PSS_SUM'],
                    'PV_1L' => $everyData['PV_1L_SUM'],
                    'PV_2L' => $everyData['PV_2L_SUM'],
                    'PV_3L' => $everyData['PV_3L_SUM'],
                    'PV_4L' => $everyData['PV_4L_SUM'],
                    'PV_5L' => $everyData['PV_5L_SUM'],
                    //总数据，历史+本期。不能用上月加本月，因为上月可能没业绩，上上个月有业绩。
                    'PV_1L_TOTAL' => $periodPerf['PV_1L'] + $userLastPerf['PV_1L'],
                    'PV_2L_TOTAL' => $periodPerf['PV_2L'] + $userLastPerf['PV_2L'],
                    'PV_3L_TOTAL' => $periodPerf['PV_3L'] + $userLastPerf['PV_3L'],
                    'PV_4L_TOTAL' => $periodPerf['PV_4L'] + $userLastPerf['PV_4L'],
                    'PV_5L_TOTAL' => $periodPerf['PV_5L'] + $userLastPerf['PV_5L'],
                    'PV_PSS_TOTAL' => $periodPerf['PV_PSS'] + $userLastPerf['PV_PSS_TOTAL'],
                ];

                // 把会员的月业绩写入缓存中，以便下面的奖金计算从缓冲中获取数据效率高
                CalcCache::addHasMonthPerfUsers($userId, $this->_periodNum);
                CalcCache::nowMonthPerf($userId, $this->_periodNum, $nowMonthPerf);

                unset($userId, $everyData, $nowMonthPerf, $lastMonthData, $userBaseInfo, $isVip);
            }
            unset($allData);
            $this->loopCalcMonthPerfTableData($offset + $this->_limit);
        }

        unset($allData);
        return true;
    }

    /**
     * 循环有业绩会员，并入库
     * @param int $offset
     * @return bool
     * @throws \yii\db\Exception
     */
    public function loopWriteNowPerf($offset = 0) {
        echo sprintf("时间:[%s]缓存本期业绩数据入库，当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
        // 从缓存列表里面从底层往上倒序获取会员
        $allData = CalcCache::getHasPerfUsers($this->_periodNum, $offset, $this->_limit);
        if($allData){
            $insertDataPeriodPerf = [];
            foreach($allData as $userId){
                $insertDataPeriodPerf[] = $this->nowPeriodPerfData($userId);
                unset($userId);
            }
            PerfPeriod::batchInsert($insertDataPeriodPerf);

            unset($insertDataPeriodPerf, $allData);
            return $this->loopWriteNowPerf($offset + $this->_limit);
        }
        unset($allData);
        return true;
    }

    /**
     * 循环有月业绩会员，并入库
     * @param int $offset
     * @return bool
     * @throws \yii\db\Exception
     */
    public function loopWriteMonthPerf($offset = 0) {
        if(!$this->_isCalcMonth){
            return true;
        }
        echo sprintf("时间:[%s]缓存本月业绩数据入库，当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
        // 从缓存列表里面从底层往上倒序获取会员
        $allData = CalcCache::getHasMonthPerfUsers($this->_periodNum, $offset, $this->_limit);
        if($allData){
            $insertDataMonthPerf = [];
            foreach($allData as $userId){
                $insertDataMonthPerf[] = $this->nowMonthPerfData($userId);
                unset($userId);
            }

            PerfMonth::batchInsert($insertDataMonthPerf);
            unset($insertDataMonthPerf, $allData);
            return $this->loopWriteMonthPerf($offset + $this->_limit);
        }
        unset($allData);
        return true;
    }

    /**
     * 本期业绩数据
     * @param $userId
     * @return array
     */
    public function nowPeriodPerfData($userId){
        $data = CalcCache::nowPeriodPerf($userId, $this->_periodNum);
        $userInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
        $result = [
            'ID' => SnowFake::instance()->generateId(),
            'USER_ID' => $userId,
            'FX_AMOUNT_CASH' => $data['FX_AMOUNT_CASH'],
            'PV_PCS' => $data['PV_PCS'],
            'PV_PSS' => $data['PV_PSS'],
            'PV_PCS_ZC' => $data['PV_PCS_ZC'],
            'PV_PCS_FX' => $data['PV_PCS_FX'],
            'PV_PCS_FX_CASH' => $data['PV_PCS_FX_CASH'],
            'PV_PCS_FX_POINT' => $data['PV_PCS_FX_POINT'],
            'PV_1L' => $data['PV_1L'],
            'PV_1L_TOUCH' => $data['PV_1L_TOUCH'],
            'PV_1L_ZC' => $data['PV_1L_ZC'],
            'PV_1L_FX' => $data['PV_1L_FX'],
            'PV_2L' => $data['PV_2L'],
            'PV_2L_TOUCH' => $data['PV_2L_TOUCH'],
            'PV_2L_ZC' => $data['PV_2L_ZC'],
            'PV_2L_FX' => $data['PV_2L_FX'],
            'PV_3L' => $data['PV_3L'],
            'PV_3L_TOUCH' => $data['PV_3L_TOUCH'],
            'PV_3L_ZC' => $data['PV_3L_ZC'],
            'PV_3L_FX' => $data['PV_3L_FX'],
            'PV_4L' => $data['PV_4L'],
            'PV_4L_TOUCH' => $data['PV_4L_TOUCH'],
            'PV_4L_ZC' => $data['PV_4L_ZC'],
            'PV_4L_FX' => $data['PV_4L_FX'],
            'PV_5L' => $data['PV_5L'],
            'PV_5L_TOUCH' => $data['PV_5L_TOUCH'],
            'PV_5L_ZC' => $data['PV_5L_ZC'],
            'PV_5L_FX' => $data['PV_5L_FX'],
            'SURPLUS_1L' => $data['SURPLUS_1L'],
            'SURPLUS_2L' => $data['SURPLUS_2L'],
            'SURPLUS_3L' => $data['SURPLUS_3L'],
            'SURPLUS_4L' => $data['SURPLUS_4L'],
            'SURPLUS_5L' => $data['SURPLUS_5L'],
            'PERIOD_NUM' => $this->_periodNum,
            'CALC_MONTH' => $this->_calcYearMonth,
            'CREATED_AT' => Date::nowTime(),
            'LAST_EMP_LV' => $userInfo['LAST_EMP_LV']
        ];
        unset($data);
        return $result;
    }



    /**
     * 本月业绩
     * @param $userId
     * @return array
     */
    public function nowMonthPerfData($userId){
        $data = CalcCache::nowMonthPerf($userId, $this->_periodNum);
        $baseInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
        $result = [
            'ID' => SnowFake::instance()->generateId(),
            'USER_ID' => $userId,
            'FX_AMOUNT_CASH' => $data['FX_AMOUNT_CASH'],
            'PV_PCS' => $data['PV_PCS'],
            'PV_PCS_FX' => $data['PV_PCS_FX'],
            'PV_PSS' => $data['PV_PSS'],
            'PV_1L' => $data['PV_1L'],
            'PV_2L' => $data['PV_2L'],
            'PV_3L' => $data['PV_3L'],
            'PV_4L' => $data['PV_4L'],
            'PV_5L' => $data['PV_5L'],
            'PV_1L_TOTAL' => $data['PV_1L_TOTAL'],
            'PV_2L_TOTAL' => $data['PV_2L_TOTAL'],
            'PV_3L_TOTAL' => $data['PV_3L_TOTAL'],
            'PV_4L_TOTAL' => $data['PV_4L_TOTAL'],
            'PV_5L_TOTAL' => $data['PV_5L_TOTAL'],
            'PV_PSS_TOTAL' => $data['PV_PSS_TOTAL'],
            'CALC_MONTH' => $this->_calcYearMonth,
            'CREATED_AT' => Date::nowTime(),
            'LAST_EMP_LV' => $baseInfo['LAST_EMP_LV']
        ];
        unset($data);
        return $result;
    }

    /**
     * 循环父级并执行回调函数
     * @param $userId
     * @param callable $callbackFunc
     * @param int $offset
     * @return bool
     */
    public function loopNetworkParentDo($userId, callable $callbackFunc, int $offset = 0) {
        $allParents = Cache::getAllNetworkParents($userId, true);
        $allData = array_slice($allParents, $offset, $this->_limit);
        unset($allParents);
        if ($allData) {
            foreach ($allData as $data) {
                $funcResult = $callbackFunc($data);
                if ($funcResult === self::LOOP_FINISH) {
                    return true;
                } elseif ($funcResult === self::LOOP_CONTINUE) {
                    continue;
                }
                unset($data, $funcResult);
            }
            unset($allData);
            return $this->loopNetworkParentDo($userId, $callbackFunc, $offset + $this->_limit);
        }
        return true;
    }

    /**
     * 循环推荐网络的父级
     * @param $userId
     * @param callable $callbackFunc
     * @param int $offset
     * @return bool
     */
    public function loopRelationParentDo($userId, callable $callbackFunc, int $offset = 0) {
        $allParents = Cache::getAllRelationParents($userId,true);
        $allData = array_slice($allParents, $offset, $this->_limit);
        unset($allParents);
        if ($allData) {
            foreach ($allData as $data) {
                $funcResult = $callbackFunc($data);
                if ($funcResult === self::LOOP_FINISH) {
                    return true;
                } elseif ($funcResult === self::LOOP_CONTINUE) {
                    continue;
                }
                unset($data, $funcResult);
            }

            unset($allData);
            return $this->loopRelationParentDo($userId, $callbackFunc, $offset + $this->_limit);
        }
        return true;
    }

    /**
     * 更新百分比并发送
     * @param $percent
     */
    private function _updatePercent($percent) {
        // 把数据写入数据库中
        Period::updateAll(['PERF_PERCENT' => $percent], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
    }

    // 期业绩表,增加是否活跃字段判断，就用isPerfActive 方法进行判断。

    /**
     * @throws \yii\db\Exception
     */
    public function loopUpdatePeriodActive($offset = 0) {
        echo sprintf("时间:[%s]更新期业绩表活跃状态字段，当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
        $allData = PerfPeriod::findUseDbCalc()
        ->where('PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum])
        ->offset($offset)
        ->limit($this->_limit)
        ->asArray()
        ->all();
        if ($allData) {
            foreach ($allData as $data) {
                $isActive = User::isPerfActive($data['USER_ID'], $this->_periodNum, $this->_calcYearMonth);
                // 期结算结果
                PerfPeriod::updateAll(['IS_ACTIVE' => $isActive], 'USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM', 
                    [
                        ':USER_ID' => $data['USER_ID'],
                        ':PERIOD_NUM' => $this->_periodNum
                    ]
                );
            }
            unset($allData);
            return $this->loopUpdatePeriodActive($offset + $this->_limit);
        }
        unset($allData);
        return true;
    }
}