<?php
namespace common\models\forms;

use common\helpers\bonus\BonusCalc;
use common\helpers\bonus\BonusSend;
use common\helpers\bonus\PerfCalc;
use common\helpers\Cache;
use common\helpers\Date;
use common\components\Model;
use common\helpers\Form;
use common\models\Period;
use common\models\UserWallet;
use common\models\User;
use common\models\UserStatusAudit;
use common\models\Withdraw;
use yii\base\Exception;

/**
 * Login form
 */
class PeriodForm extends Model
{
    public $periodNum;

    private $_periodModel;
    private $_limit = 1000;

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['periodNum'], 'trim'],
            [['periodNum'], 'required'],
            [['periodNum'], 'integer'],
            [['periodNum'], 'isPeriod'],
        ];
    }

    public function scenarios()
    {
        $parentScenarios =  parent::scenarios();
        $customScenarios = [
            'close' => ['periodNum'],
            'perf' => ['periodNum'],
            'calc' => ['periodNum'],
            'send' => ['periodNum'],
            'autoClose' => ['periodNum'],
        ];
        return array_merge($parentScenarios, $customScenarios);
    }

    public function attributeLabels()
    {
        return [
            'periodNum' => '期数',
        ];
    }

    public function isPeriod($attributes){
        $periodObj = Period::instance();
        $periodModel = Period::findOne(['PERIOD_NUM' => $this->periodNum]);
        if(!$periodModel){
            $this->addError($attributes, '所传期数不存在');
        }
        if($this->scenario == 'close') {
            if(!$periodObj->isCanClose($this->periodNum)){
                $this->addError($attributes, '所传期数不可封期');
            }
        }
        elseif($this->scenario == 'perf') {
            if(!$periodObj->isCanPerf($this->periodNum)){
                $this->addError($attributes, '所传期数不可生成业绩单');
            }
        }
        elseif($this->scenario == 'calc') {
            if(!$periodObj->isCanCalc($this->periodNum)){
                $this->addError($attributes, '所传期数不可结算');
            }
        }
        elseif($this->scenario == 'send') {
            if(!$periodObj->isCanSend($this->periodNum)){
                $this->addError($attributes, '所传期数不可挂网');
            }
        }

        $this->_periodModel = $periodModel;
    }

    /**
     * 封期
     * @return null
     * @throws \yii\db\Exception
     */
    public function closePeriod(){
        if(!$this->validate()){
            return null;
        }
        $periodNum = $this->periodNum;
        // 进行封期操作
        $transaction = \Yii::$app->db->beginTransaction();
        try {
            $model = $this->_periodModel;
            $model->IS_CLOSED = 1;
            if(isset(\Yii::$app->user->id) && \Yii::$app->user->id){
                $model->CLOSE_ADMIN_ID = \Yii::$app->user->id;
            }
            $model->CLOSED_AT = Date::nowTime();
            if(!$model->save()){
                throw new Exception('封期失败，请重试');
            }

            $settings = \Yii::$app->params['swooleAsyncTimer'];
            $bonusSettings = \Yii::$app->params['swooleBonusConfig'];
            $settings = array_merge($settings, $bonusSettings);
            $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('bonus/after-close', ['periodNum'=>$periodNum, 'closedAt'=>$model->CLOSED_AT], $settings);
            if($taskKey === false){
                $this->addError('send', '请求失败');
                return null;
            }

            $transaction->commit();
        } catch (Exception $e){
            $transaction->rollBack();
            $this->addError('close', $e->getMessage());
            return null;
        }

        return $periodNum;
    }

    /**
     * 自动封期
     * @return null
     * @throws \yii\db\Exception
     */
    public function autoClosePeriod(){
        if(!$this->validate()){
            return null;
        }
        $periodNum = $this->periodNum;
        // 进行封期操作
        $transaction = \Yii::$app->db->beginTransaction();
        try {
            $model = $this->_periodModel;
            $model->IS_CLOSED = 1;
            if(isset(\Yii::$app->user->id) && \Yii::$app->user->id){
                $model->CLOSE_ADMIN_ID = \Yii::$app->user->id;
            }
            $model->CLOSED_AT = Date::nowTime();
            if(!$model->save()){
                throw new Exception('封期失败，请重试');
            }

            $transaction->commit();
        } catch (Exception $e){
            $transaction->rollBack();
            $this->addError('close', $e->getMessage());
            return null;
        }

        //封期后的操作（这句话放这里的目的是为了保障封期的时间不受其他后期工作的影响，封期之后再完成封期后的操作）
        $this->afterCloseAsync($periodNum, $model->CLOSED_AT);

        return $periodNum;
    }

    /**
     * 给到期要加T的会员加T
     * @param $periodNum
     */
    private function _periodChangeStatus($periodNum){
        // 到期加T
        $allAddTData = UserStatusAudit::find()->where('IS_PERIOD_ADD_T=1 AND ADD_T_PERIOD_NUM<=:NOW_PERIOD_NUM AND AUDIT_STATUS=:AUDIT_STATUS', [':NOW_PERIOD_NUM'=>$periodNum, ':AUDIT_STATUS'=>\Yii::$app->params['auditStatus']['true']['value']])->asArray()->all();
        foreach($allAddTData as $data){
            User::updateAll(['ID_CARD_PREFIX'=>'T'], 'ID=:ID', [':ID'=>$data['USER_ID']]);
        }
        // 到期开通
        $allOpenData = UserStatusAudit::find()->where('IS_PERIOD_OPEN=1 AND OPEN_PERIOD_NUM<=:NOW_PERIOD_NUM AND AUDIT_STATUS=:AUDIT_STATUS', [':NOW_PERIOD_NUM'=>$periodNum, ':AUDIT_STATUS'=>\Yii::$app->params['auditStatus']['true']['value']])->asArray()->all();
        foreach($allOpenData as $openData){
            // 改变会员的状态 并取消身份证号加T，并设置首次开通标记
            User::updateAll(['STATUS'=>$openData['STATUS_VALUE'], 'STATUS_AT'=>Date::nowTime(), 'ID_CARD_PREFIX'=>'', 'IS_FIRST_OPEN'=>1], 'ID=:ID', [':ID'=>$openData['USER_ID']]);
            //从关停到开启
            if ($openData['ORI_VALUE'] == UserStatusForm::STATUS_CLOSE) {
                UserWallet::updateAll(['CLEAR_BY_CLOSED_AT' => 0], 'USER_ID=:USER_ID', [':USER_ID' => $openData['USER_ID']]);
            }
        }
    }


    /**
     * 页面请求异步处理编辑
     * @return string | null
     */
    public function calcWebToAsync(){
        if(!$this->validate()){
            return null;
        }
        // 把正在结算标记为真
        $model = $this->_periodModel;
        $model->IS_CALCING = 1;
        $model->CALC_ADMIN_ID = \Yii::$app->user->id;
        if(!$model->save()){
            $this->addError('calc', Form::formatErrorsForApi($model->getErrors()));
            return null;
        }
        // 异步处理添加任务
        $settings = \Yii::$app->params['swooleAsyncTimer'];
        $bonusSettings = \Yii::$app->params['swooleBonusConfig'];
        $settings = array_merge($settings, $bonusSettings);
        $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('bonus/calc', \Yii::$app->request->get(), $settings);
        if($taskKey === false){
            $this->addError('send', '请求失败');
            return null;
        }
        return $model;
    }

    /**
     * 异步处理逻辑
     * @param $handleUserId
     * @return bool|null
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public function calcAsync($handleUserId){
        if(!$this->validate()){
            return null;
        }
        $bonusCalc = BonusCalc::instance();
        //$bonusCalc->init($this->periodNum, $handleUserId);
        //$bonusCalc->setPeriodNum($this->periodNum);
        $asyncResult = $bonusCalc->calcStep($this->periodNum, $handleUserId);
        if($asyncResult){
            $bonusCalc->endCalcTask();
        } else {
            $bonusCalc->errorCalcTask();
            $this->addErrors($bonusCalc->getErrors());
        }
        return $asyncResult;
    }

    /**
     * 页面请求异步处理生成业绩单
     * @return string | null
     */
    public function perfWebToAsync(){
        if(!$this->validate()){
            return null;
        }
        // 把正在结算标记为真
        $model = $this->_periodModel;
        $model->IS_PERFING = 1;
        $model->PERF_ADMIN_ID = \Yii::$app->user->id;
        if(!$model->save()){
            $this->addError('perf', Form::formatErrorsForApi($model->getErrors()));
            return null;
        }
        // 异步处理添加任务
        $settings = \Yii::$app->params['swooleAsyncTimer'];
        $bonusSettings = \Yii::$app->params['swooleBonusConfig'];
        $settings = array_merge($settings, $bonusSettings);
        $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('bonus/perf', \Yii::$app->request->get(), $settings);
        if($taskKey === false){
            $this->addError('perf', '请求失败');
            return null;
        }
        return $model;
    }

    /**
     * 异步处理逻辑
     * @param $handleUserId
     * @return bool|null
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public function perfAsync($handleUserId){
        if(!$this->validate()){
            return null;
        }
        $bonusCalc = PerfCalc::instance();
        //$bonusCalc->init($this->periodNum, $handleUserId);
        //$bonusCalc->setPeriodNum($this->periodNum);
        $asyncResult = $bonusCalc->calcStep($this->periodNum, $handleUserId);
        if($asyncResult){
            $bonusCalc->endCalcTask();
        } else {
            $bonusCalc->errorCalcTask();
            $this->addErrors($bonusCalc->getErrors());
        }
        return $asyncResult;
    }

    /**
     * 页面请求异步处理挂网
     * @return string | null
     */
    public function sendWebToAsync(){
        if(!$this->validate()){
            return null;
        }
        // 把正在挂网标记设为真
        $model = $this->_periodModel;
        $model->IS_SENDING = 1;
        $model->SENT_ADMIN_ID = \Yii::$app->user->id;
        if(!$model->save()){
            $this->addError('send', Form::formatErrorsForApi($model->getErrors()));
            return null;
        }
        // 异步处理添加任务
        $settings = \Yii::$app->params['swooleAsyncTimer'];
        $bonusSettings = \Yii::$app->params['swooleBonusConfig'];
        $settings = array_merge($settings, $bonusSettings);
        $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('bonus/send', \Yii::$app->request->get(), $settings);
        if($taskKey === false){
            $this->addError('send', '请求失败');
            return null;
        }
        return $model;
    }

    /**
     * 异步处理挂网逻辑
     * @param $handleUserId
     * @return bool|null
     */
    public function sendAsync($handleUserId){
        if(!$this->validate()){
            return null;
        }
        $bonusSend = BonusSend::instance();
        $bonusSend->init($this->periodNum, $handleUserId);
        $asyncResult = $bonusSend->sendStep();
        if($asyncResult){
            $bonusSend->endTask();
        } else {
            $bonusSend->errorTask();
            $this->addErrors($bonusSend->getErrors());
        }
        return $asyncResult;
    }

    /**
     * 异步处理封期后的操作
     * @param $periodNum
     * @return bool
     * @throws \yii\db\Exception
     */
    public function afterCloseAsync($periodNum,$closedAt){
        //如果自动结算
//        if(boolval(Cache::getSystemConfig()['autoCalcPeriod']['VALUE'])){
//            $period = Period::instance();
//            if($period->isLastSent($periodNum)) {
//                $bonusCalc = PerfCalc::instance();
//                $asyncResult = $bonusCalc->calcStep($periodNum);
//                if ($asyncResult) {
//                    $bonusCalc->endCalcTask();
//                } else {
//                    $bonusCalc->errorCalcTask();
//                    $this->addErrors($bonusCalc->getErrors());
//                }
//                return $asyncResult;
//            }
//        }
    }

}
