<?php
/**
 * Created by PhpStorm.
 * User: liyunlong
 * Date: 2019-01-30
 * Time: 14:21
 */

namespace common\helpers\user;


use common\helpers\Cache;
use common\helpers\Date;
use common\helpers\Tool;
use common\models\PerfMonth;
use common\models\Period;
use common\models\ReconsumePool;
use common\models\ReconsumePoolFlow;
use common\models\DeclarationLevel;
use common\models\EmployLevel;
use common\models\User;
use yii\base\Exception;
use yii\db\Expression;

class Reconsume {

    const TYPE_DEC = 1;
    const TYPE_CALC = 2;
    const TYPE_AUDIT_PV = 3;
    const TYPE_AUDIT_MONTH = 4;
    const TYPE_MANUAL = 5;
    const TYPE_RESEND_QY = 7;
    const TYPE = [
        1 => ['label' => '报单预存', 'value' => 1],
        2 => ['label' => '结算自动扣除', 'value' => 2],
        3 => ['label' => '调整复销池余额', 'value' => 3],
        4 => ['label' => '调整复销池月数', 'value' => 4],
        5 => ['label' => '手工扣除月复销', 'value' => 5],
        //7 => ['label' => '补发区域津贴', 'value' => 7],
    ];

    /**
     * 可用复销余额
     * @param $userId
     * @return mixed
     */
    public static function getBalance($userId) {
        $oneData = ReconsumePool::findOneAsArray('USER_ID=:USER_ID', [':USER_ID' => $userId], 'UNUSED_PV');
        return $oneData['UNUSED_PV'];
    }

    /**
     * 增加复销或扣除复销池的PV
     * @param $userId
     * @param $pv
     * @param array $params
     * @param bool $mustHasUser
     * 该参数主要用于批量报单，复销会员是新首购的新会员，数据库中不存在该会员，此时不能要求一定存在会员，然后先把复销池数据插进去
     * @return int
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public static function changePoolPV($userId, $pv, $params = [], $mustHasUser = true) {
        if ($pv == 0) return 0;
        $period = Period::instance();
        if (!isset($params['PERIOD_NUM'])) {
            $periodNum = $period->getNowPeriodNum();
        } else {
            $periodNum = $params['PERIOD_NUM'];
        }
        $calcYearMonth = $period->getYearMonth($periodNum);
        // 查看是否有数据
        if (!ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->exists()) {
            // 新建一条用户的复销池数据
            ReconsumePool::insertOne(['USER_ID' => $userId, 'CREATED_AT' => Date::nowTime()]);
        }
        // 如果扣除pv的话，检测是否够扣，不够扣，则返回0
        if ($pv < 0) {
            $oneDataBefore = ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
            if ($oneDataBefore['UNUSED_PV'] < abs($pv)) {
                throw new Exception('复销池余额不足');
            }
        }
        $updateData = [];
        $updateData['UNUSED_PV'] = new Expression("UNUSED_PV + $pv");
        // 变更复销池Pv
        ReconsumePool::updateAll($updateData, 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
        unset($updateData);
        // 获取变更完的数据
        $oneDataAfter = ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        // 记录流水
        if($mustHasUser){
            $userInfo = Info::baseInfo($userId);
        } else {
            $userInfo =[
                'DEC_LV' => DeclarationLevel::getDefaultLevelId(),
                'EMP_LV' => EmployLevel::getDefaultLevelId(),
                'STATUS' => 1,
            ];
        }
        $flowInsertData = [
            'RECONSUME_POOL_SN' => ReconsumePoolFlow::generateSN(),
            'USER_ID' => $userId,
            'LAST_DEC_LV' => $userInfo['DEC_LV'],
            'LAST_EMP_LV' => $userInfo['EMP_LV'],
            'LAST_STATUS' => $userInfo['STATUS'],
            'DEAL_TYPE' => $params['DEAL_TYPE'],
            'RECONSUME_POOL_TYPE' => ReconsumePoolFlow::POOL_TYPE_PV,
            'DEDUCT_PV' => $pv,
            'UNUSED_PV' => $oneDataAfter['UNUSED_PV'],
            'UNUSED_MONTH' => $oneDataAfter['UNUSED_MONTH'],
            'REMARK' => $params['REMARK'] ?? null,
            'REMARK_IS_SHOW' => $params['REMARK_IS_SHOW'] ?? 1,
            'PERIOD_NUM' => $periodNum,
            'CALC_MONTH' => $calcYearMonth,
            'P_CALC_MONTH' => Date::ociToDate($calcYearMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH),
            'CREATED_AT' => Date::nowTime(),
            'ADMIN_NAME' => $params['ADMIN_NAME'] ?? null,
        ];

        ReconsumePoolFlow::insertOne($flowInsertData);
        unset($flowInsertData);
        return $pv;
    }

    /**
     * 扣除月复销
     * @param $userId
     * @param $periodNum
     * @param array $params
     * @return bool
     * @throws \yii\db\Exception
     */
    public static function deductFx($userId, $periodNum, array $params = []) {
        $period = Period::instance();
        $calcYearMonth = $period->getYearMonth($periodNum);
        return self::deductFxByCalcMonth($userId, $calcYearMonth, $params);
    }

    /**
     * 通过结算月来扣复销
     * @param $userId
     * @param $calcYearMonth
     * @param array $params
     * @return bool
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public static function deductFxByCalcMonth($userId, $calcYearMonth, array $params = []) {
        $sysConfig = Cache::getSystemConfig();
        $pv = $sysConfig['reConsumePerf']['VALUE'];

        // 看是否本月注册，本月注册不扣除@190904
        if(Status::isMonthJoin($userId,$calcYearMonth)) return true;

        // 查看是否有数据
        if (!ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->exists()) {
            // 新建一条用户的复销池数据
            ReconsumePool::insertOne(['USER_ID' => $userId, 'CREATED_AT' => Date::nowTime()]);
        }
        // 查看这个月是否已经扣过了，如果扣过了就不在扣了！直接返回扣除过的业绩
        $isDeducted = ReconsumePoolFlow::find()->yearMonth($calcYearMonth)->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND IS_FX_DEDUCT=1', [':USER_ID' => $userId, ':CALC_MONTH' => $calcYearMonth])->asArray()->one();
        if ($isDeducted) {
            return true;
        }
        // 检测是否够扣，不够扣，则扣除月有效期
        $deductPv = 0;
        $deductMonth = 0;
        $oneDataBefore = ReconsumePool::find()->select('UNUSED_PV,UNUSED_MONTH')->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        if ($oneDataBefore['UNUSED_PV'] < abs($pv)) {
            if ($oneDataBefore['UNUSED_MONTH'] < abs(1)) {
                return false;
            } else {
                $deductMonth = 1;
            }
        } else {
            $deductPv = $pv;
        }
        $updateData = [];
        $updateData['UNUSED_PV'] = new Expression("UNUSED_PV - $deductPv");
        $updateData['UNUSED_MONTH'] = new Expression("UNUSED_MONTH - $deductMonth");
        // 变更复销池Pv
        ReconsumePool::updateAll($updateData, 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
        // 获取变更完的数据
        $oneDataAfter = ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        // 获取该结算月的最大期数，即为结算月的期节点
        $periodNum = Period::getPeriodNumPointFromMonth(substr($calcYearMonth, 0, 4), intval(substr($calcYearMonth, 4, 2)));
        // 记录流水
        $userInfo = Info::baseInfo($userId);
        $flowInsertData = [
            'RECONSUME_POOL_SN' => ReconsumePoolFlow::generateSN(),
            'USER_ID' => $userId,
            'LAST_DEC_LV' => $userInfo['DEC_LV'],
            'LAST_EMP_LV' => $userInfo['EMP_LV'],
            'LAST_STATUS' => $userInfo['STATUS'],
            'DEAL_TYPE' => $params['DEAL_TYPE'],
            'RECONSUME_POOL_TYPE' => $deductMonth != 0 ? ReconsumePoolFlow::POOL_TYPE_MONTH : ReconsumePoolFlow::POOL_TYPE_PV,
            'DEDUCT_PV' => $deductPv == 0 ? 0 : -$deductPv,
            'DEDUCT_MONTH' => $deductMonth == 0 ? 0 : -$deductMonth,
            'UNUSED_PV' => $oneDataAfter['UNUSED_PV'],
            'UNUSED_MONTH' => $oneDataAfter['UNUSED_MONTH'],
            'IS_FX_DEDUCT' => 1,
            'REMARK' => $params['REMARK'] ?? null,
            'REMARK_IS_SHOW' => $params['REMARK_IS_SHOW'] ?? 1,
            'PERIOD_NUM' => $periodNum,
            'CALC_MONTH' => $calcYearMonth,
            'P_CALC_MONTH' => Date::ociToDate($calcYearMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH),
            'CREATED_AT' => Date::nowTime(),
            'ADMIN_NAME' => $params['ADMIN_NAME'] ?? 'system',
        ];
        ReconsumePoolFlow::insertOne($flowInsertData);
        unset($oneDataBefore, $updateData, $oneDataAfter, $flowInsertData);
        return true;
    }

    /**
     * 查看该会员是否能扣除复销
     * @param $userId
     * @param $calcYearMonth
     * @return bool
     * @throws \yii\db\Exception
     */
    public static function isCanDeduct($userId, $calcYearMonth) {
        // 查看会员是否本月加入
        if (Status::isMonthJoin($userId, $calcYearMonth)) return false;
        // 会员未加入的结算月不允许扣除
        if (Status::afterMonthJoin($userId, $calcYearMonth)) return false;
        // 查看该结算月是否已经扣过
        return !(ReconsumePoolFlow::find()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND IS_FX_DEDUCT=1', [':USER_ID' => $userId, ':CALC_MONTH' => $calcYearMonth])->exists());
    }

    /**
     * 是否有得奖资格
     * @param $userId
     * @param $calcYearMonth
     * @return bool
     * @throws \yii\db\Exception
     */
    public static function isCanGetBonus($userId, $calcYearMonth) {
        // 查看会员是否本月加入
        if (Status::isMonthJoin($userId, $calcYearMonth)) return true;
        // 查看会员上月是否已经扣除过复销
        $periodNum = Period::getPeriodNumPointFromMonth(substr($calcYearMonth, 0, 4), intval(substr($calcYearMonth, 4, 2)));
        $period = Period::instance();
        $lastMonth = $period->getLastMonth($periodNum);
        // 查看业绩表中该结算月的上个月是否有复销资格
        return PerfMonth::find()->yearMonth($lastMonth['yearMonth'])->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND FX_STATUS=1', [':USER_ID' => $userId, ':CALC_MONTH' => $lastMonth['yearMonth']])->exists();
//        return ReconsumePoolFlow::find()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND IS_FX_DEDUCT=1', [':USER_ID'=>$userId, ':CALC_MONTH'=>$lastMonth['yearMonth']])->exists();
    }

    /**
     * 变化有效月数
     * @param $userId
     * @param $monthNum
     * @param array $params
     * @return int
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public static function changePoolMonthNum($userId, $monthNum, array $params = []) {
        $periodNum = $params['periodNum'] ?? null;
        if ($monthNum == 0) return 0;
        $period = Period::instance();
        if (!$periodNum) {
            $periodNum = $period->getNowPeriodNum();
        }
        $calcYearMonth = $period->getYearMonth($periodNum);
        // 查看是否有数据
        if (!ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->exists()) {
            // 新建一条用户的复销池数据
            ReconsumePool::insertOne(['USER_ID' => $userId, 'CREATED_AT' => Date::nowTime()]);
        }
        // 如果扣除pv的话，检测是否够扣，不够扣，则返回0
        if ($monthNum < 0) {
            $oneDataBefore = ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
            if ($oneDataBefore['UNUSED_MONTH'] < abs($monthNum)) {
                throw new Exception('复销池剩余月数不足');
            }
        }
        // 增加月份数
        $updateData = [];
        $updateData['UNUSED_MONTH'] = new Expression("UNUSED_MONTH + $monthNum");
        // 变更复销池Pv
        ReconsumePool::updateAll($updateData, 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
        // 获取变更完的数据
        $oneDataAfter = ReconsumePool::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        // 记录流水
        $userInfo = Info::baseInfo($userId);
        $flowInsertData = [
            'RECONSUME_POOL_SN' => ReconsumePoolFlow::generateSN(),
            'USER_ID' => $userId,
            'LAST_DEC_LV' => $userInfo['DEC_LV'],
            'LAST_EMP_LV' => $userInfo['EMP_LV'],
            'LAST_STATUS' => $userInfo['STATUS'],
            'DEAL_TYPE' => $params['DEAL_TYPE'],
            'RECONSUME_POOL_TYPE' => ReconsumePoolFlow::POOL_TYPE_MONTH,
            'DEDUCT_MONTH' => $monthNum,
            'UNUSED_PV' => $oneDataAfter['UNUSED_PV'],
            'UNUSED_MONTH' => $oneDataAfter['UNUSED_MONTH'],
            'REMARK' => $params['REMARK'] ?? null,
            'REMARK_IS_SHOW' => $params['REMARK_IS_SHOW'] ?? 1,
            'PERIOD_NUM' => $periodNum,
            'CALC_MONTH' => $calcYearMonth,
            'P_CALC_MONTH' => Date::ociToDate($calcYearMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH),
            'CREATED_AT' => Date::nowTime(),
            'ADMIN_NAME' => $params['ADMIN_NAME'] ?? null,
        ];

        ReconsumePoolFlow::insertOne($flowInsertData);
        unset($updateData, $oneDataAfter, $flowInsertData);
        return $monthNum;
    }

    /**
     * 获取复销剩余时间
     * @param $userId
     * @return array
     * @throws \yii\db\Exception
     */
    public static function getUserReconsumePool($userId) {
        $pool = ReconsumePool::findUseSlaves()->select('UNUSED_PV,UNUSED_MONTH')->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        if (!$pool) {
            $pool['UNUSED_PV'] = 0;
            $pool['UNUSED_MONTH'] = 0;
            /*return [
                'unusedPV' => 0,
                'unusedMonth' => 0,
                'reConsumeTimes' => 0,
                'toTime' => 0,
                'toDate' => 0,
            ];*/
        }
        // 第一步 获取复销剩余总月数
        $systemConfig = Cache::getSystemConfig();
        $reConsumePerf = $systemConfig['reConsumePerf']['VALUE'];
        if ($reConsumePerf <= 0) {
            return ['unusedPV' => 0,
                'unusedMonth' => 0,
                'reConsumeTimes' => 0,
                'toTime' => 0,
                'toDate' => 0,
                'isPass' => 0,
            ];
        }
        $reConsumeTimes = intval($pool['UNUSED_PV'] / $reConsumePerf);
        $reConsumeTimes += $pool['UNUSED_MONTH'];

        // 第二步 获取最近一次未挂网的结算月
        $period = Period::instance();
        $sentMaxPeriodNum = Period::sentMaxPeriodNum() + 1;
        $sentYear = $period->getYear($sentMaxPeriodNum);
        $sentMonth = Tool::numFix($period->getMonth($sentMaxPeriodNum), 2);
        $sentYearMonth = $period->getYearMonth($sentMaxPeriodNum);

        //看会员这个月是否复销
        if (ReconsumePoolFlow::find()->yearMonth($sentYearMonth)->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND IS_FX_DEDUCT=1', [':USER_ID' => $userId, ':CALC_MONTH' => $sentYearMonth])->asArray()->one()) {
            //已扣复销当前月15日为时间基点
            $baseDate = $sentYear . '-' . $sentMonth . '-15';
            $reConsumeTimes += 1;
        } else {
            //获取上一个结算月
            $lastMonth = $period->getLastMonth($sentMaxPeriodNum);
            $baseDate = $lastMonth['year'] . '-' . $lastMonth['month'] . '-15';
            //是否本月注册会员
            if (Status::isMonthJoin($userId, $sentYearMonth)) {
                $reConsumeTimes += 2;
            } //是否上月注册会员
            elseif (Status::isMonthJoin($userId, $lastMonth['yearMonth'])) {
                $reConsumeTimes += 1;
            } elseif (Status::afterMonthJoin($userId, $sentYearMonth)){
                $reConsumeTimes +=Period::getMonthNum($sentMaxPeriodNum,Info::getPeriodNumByUserId($userId));
                $reConsumeTimes +=1;
            } else {
                //是否扣复销
                if (!ReconsumePoolFlow::find()->yearMonth($lastMonth['yearMonth'])->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH AND IS_FX_DEDUCT=1', [':USER_ID' => $userId, ':CALC_MONTH' => $lastMonth['yearMonth']])->asArray()->one()) {
                    //会员过期
                    if ($reConsumeTimes <= 0) {
                        //上一次扣复销的时间
                        if ($flow = ReconsumePoolFlow::find()->select('PERIOD_NUM')->where('USER_ID=:USER_ID AND IS_FX_DEDUCT=1', [':USER_ID' => $userId])->orderBy('PERIOD_NUM DESC')->asArray()->one()) {
                            $nextMonth = $period->getNextMonth($flow['PERIOD_NUM']);
                            $overPeriod = Period::getPeriodPointFromMonth($nextMonth['year'], $nextMonth['month']);
                            $toTime = $overPeriod['END_TIME'];
                            $toPeriod = Period::getPeriodPointFromMonth($sentYear, $sentMonth);
                            $toRechargeTime = $toPeriod['END_TIME'];
                            return [
                                'unusedPV' => $pool['UNUSED_PV'],
                                'unusedMonth' => $pool['UNUSED_MONTH'],
                                'reConsumeTimes' => 0,
                                'toTime' => $toTime,
                                'toDate' => \date('Y-m-d', $toTime),
                                'toRechargeTime' => $toRechargeTime,
                                'toRechargeDate' => \date('Y-m-d', $toRechargeTime),
                                'isPass' => 0,
                            ];
                        } else {
                            $nextMonth = $period->getNextMonth(Info::getPeriodNumByUserId($userId));
                            $overPeriod = Period::getPeriodPointFromMonth($nextMonth['year'], $nextMonth['month']);
                            $toTime = $overPeriod['END_TIME'];
                            $toPeriod = Period::getPeriodPointFromMonth($sentYear, $sentMonth);
                            $toRechargeTime = $toPeriod['END_TIME'];
                            return [
                                'unusedPV' => $pool['UNUSED_PV'],
                                'unusedMonth' => $pool['UNUSED_MONTH'],
                                'reConsumeTimes' => 0,
                                'toTime' => $toTime,
                                'toDate' => \date('Y-m-d', $toTime),
                                'toRechargeTime' => $toRechargeTime,
                                'toRechargeDate' => \date('Y-m-d', $toRechargeTime),
                                'isPass' => 0,
                            ];
                        }
                    } else {
                        $baseDate = $lastMonth['year'] . '-' . $lastMonth['month'] . '-15';
                    }
                }else{
                    $reConsumeTimes += 1;
                }
            }
        }

        $calcTime = strtotime("+$reConsumeTimes month", strtotime($baseDate));

        //获取toTime结算月最后一期封期时间
        $toPeriod = Period::getPeriodFromTime($calcTime);
        $periodPoint = Period::getPeriodPointFromMonth($toPeriod['CALC_YEAR'], $toPeriod['CALC_MONTH']);
        $toTime = $periodPoint['END_TIME'];
        $toDate = $toTime?(\date('Y-m-d', $toTime)):'长期';

        $toRechargeTime = $periodPoint['END_TIME'];
        $toRechargeDate = $toRechargeTime?(\date('Y-m-d', $toRechargeTime)):'长期';
        unset($toPeriod, $toYear, $toMonth, $periodPoint);
        return [
            'unusedPV' => $pool['UNUSED_PV'],
            'unusedMonth' => $pool['UNUSED_MONTH'],
            'reConsumeTimes' => $reConsumeTimes,
            'toTime' => $toTime,
            'toDate' => $toDate,
            'toRechargeTime' => $toRechargeTime,
            'toRechargeDate' => $toRechargeDate,
            'isPass' => 1,
        ];
    }

    /**
     * 通过用户名获取会员复销池相关
     * @param $userName
     * @return array
     */
    public static function getUserReconsumePoolByUserName($userName) {
        return self::getUserReconsumePool(Info::getUserIdByUserName($userName));
    }

    /**
     * 不能扣除月复销的月份
     * @param $userId
     * @param int|null $year
     * @return array|\yii\db\ActiveRecord[]
     * @throws \yii\db\Exception
     */
    public static function cantDeductMonth($userId, int $year = null) {
        $period = Period::instance();
        $sentMaxPeriodNum = Period::sentMaxPeriodNum() + 1;
        if ($year === null) {
            $year = $period->getYear($sentMaxPeriodNum);
        }
        $allData = ReconsumePoolFlow::find()->select('CALC_MONTH')->where('USER_ID=:USER_ID AND CALC_MONTH>=:YEAR_START AND CALC_MONTH<=:YEAR_END AND IS_FX_DEDUCT=1', [':USER_ID' => $userId, ':YEAR_START' => intval($year . '01'), ':YEAR_END' => intval($year . '12')])->asArray()->all();

        //@190904 会员注册当月及以前都不能扣除
        $oneUser = User::find()->select('PERIOD_AT')->where('ID=:USER_ID', [':USER_ID'=>$userId])->asArray()->one();
        $period = Period::instance();
        $addYear = $period->getYear($oneUser['PERIOD_AT']);
        if($addYear==$year){
            $addMonth = $period->getMonth($oneUser['PERIOD_AT']);
            for($i=1;$i<=$addMonth;$i++){
                $allData[] = ['CALC_MONTH'=>$year.Tool::numFix($i, 2)];
            }
        }
        if($year == $period->getYear($sentMaxPeriodNum)){
            $sentMonth = $period->getMonth($sentMaxPeriodNum);
            for($i=$sentMonth;$i<=12;$i++){
                $allData[] = ['CALC_MONTH'=>$year.Tool::numFix($i, 2)];
            }
        }
        return $allData;
    }
}