<?php

namespace common\models\forms;

use common\helpers\Cache;
use common\helpers\Date;
use common\components\Model;
use common\helpers\Form;
use common\helpers\snowflake\SnowFake;
use common\helpers\Tool;
use common\helpers\user\Balance;
use common\helpers\user\Cash;
use common\helpers\user\Info;
use common\libs\logging\operate\UserOperate;
use common\models\Article;
use common\models\ArticleCategory;
use common\models\DealType;
use common\models\DecOrder;
use common\models\Order;
use common\models\PerfPeriod;
use common\models\Period;
use common\models\Transfer;
use common\models\User;
use common\models\UserBind;
use common\models\UserBonus;
use common\models\UserInfo;
use common\models\UserRelation;
use common\models\UserSystem;
use Yii;
use yii\base\Exception;
use yii\helpers\Json;

/**
 * Login form
 */
class TransferForm extends Model {
    const allowTransferType = [1, 2, 3];
    const BONUS_TO_BALANCE = 1;
    const BONUS_TO_BONUS = 2;
    const BALANCE_TO_BALANCE = 3;

    public $toUserName;
    public $toRealName;
    public $amount;
    public $payPassword;
    public $type;
    public $remark;
    public $transferCode;

    private $_fromUserInfo;
    private $_toUserInfo;
    private $_transferProp;
    private $_transferConfig;
    private $_fee = 0;

    public function init() {
        parent::init();
        $this->userOperateLogger = new UserOperate([
            'fetchClass' => Transfer::class,
        ]);
    }

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['toUserName', 'toRealName', 'amount', 'type', 'remark'], 'trim'],
            [['toUserName', 'toRealName', 'amount', 'type', 'payPassword', 'transferCode'], 'required'],
            [['toUserName'], 'exist', 'targetClass' => UserInfo::class, 'targetAttribute' => 'USER_NAME'],
            [['type'], 'isType'],
            [['toUserName'], 'initUser'],
            [['amount'], 'price'],
            [['amount'], 'isAmount'],
            [['transferCode'], 'validateCode'],
            [['payPassword'], 'validatePassword'],
        ];
    }

    /**
     * 指定校验场景
     * @return array
     */
    public function scenarios() {
        $parentScenarios = parent::scenarios();
        $customScenarios = [
            'transfer' => ['type', 'toUserName', 'toRealName', 'amount', 'remark', 'payPassword', 'transferCode'],
        ];
        return array_merge($parentScenarios, $customScenarios);
    }

    public function attributeLabels() {
        return [
            'toUserName' => 'Transferred Member Code', // 转入会员编号
            'amount' => 'Amount', // 金额
            'payPassword' => 'Payment Password', // 支付密码
            'transferCode' => 'Verification Code', // 转账校验码
        ];
    }

    /**
     * 初始化转入转出用户信息
     * @param $attribute
     * @return null
     * @throws Exception
     */
    public function initUser($attribute) {
        // 转账记录
        if(!$toUserId = Info::getUserIdByUserName($this->toUserName)){
            $this->addError($attribute, 'Transferred member not exists'); // 转入会员不存在
            return null;
        }
//        if(Info::getUserRealNameByUserId($toUserId)!=$this->toRealName){
//            $this->addError($attribute, '转入会员会员姓名不正确');
//            return null;
//        }
        $this->_toUserInfo = Info::baseInfo($toUserId);

        $fromUserId = \Yii::$app->user->id;
        $fromUser = Info::baseInfo($fromUserId);
        if (!$fromUser) {
            $this->addError($attribute, 'Transferred member not exists'); // 转入会员不存在
            return null;
        }

        // 不能跨国转账
        $fromCountryId = User::getEnCodeInfo($fromUserId)['COUNTRY_ID'];
        $toCountryId = User::getEnCodeInfo($toUserId)['COUNTRY_ID'];
        if ($fromCountryId != $toCountryId) {
            $this->addError($attribute, Yii::t('app',  'transferMemberDoesNotSame'));
            return null;
        }

        // 转账条件判断
        $orderAmount = Order::find()->where('USER_ID=:USER_ID', [':USER_ID' => $fromUserId])->SUM('ORDER_AMOUNT');
        $recNum = intval(DecOrder::find()->where('REC_USER_ID=:REC_USER_ID', [':REC_USER_ID' => $fromUserId])->count());
        //$recNum = UserRelation::firstFloorChildNum($fromUserId);
//        if ($orderAmount < 300 && $recNum==0) {
//            $this->addError($attribute, '消费未满300元或未推荐新人，暂不能转账');
//            return null;
//        }
        $this->_fromUserInfo = $fromUser;
        //是否同体系转账
//        if($this->_transferConfig['isSystem']==1){
//            if($this->_toUserInfo['SYSTEM_ID']!=$this->_fromUserInfo['SYSTEM_ID']){
//                $this->addError($attribute, '只能同一体系间转账');
//                return null;
//            }
//        }

        //是否点位绑定转账
//        if ($this->_transferConfig['isBind'] == 1) {
//            if (!UserBind::sameBind($this->_toUserInfo['ID'], $this->_fromUserInfo['ID'])) {
//                $this->addError($attribute, '只能点位绑定在一起的会员之间转账');
//                return null;
//            }
//        }



        //奖金转奖金限同一身份证
        /*if ($this->type == self::BONUS_TO_BONUS) {
            $toIdCard = User::findOneAsArray('ID=:ID', [':ID' => $toUser['USER_ID']], 'ID_CARD');
            $fromIdCard = User::findOneAsArray('ID=:ID', [':ID' => $fromUser['USER_ID']], 'ID_CARD');
            if ($toIdCard['ID_CARD'] && ($toIdCard['ID_CARD'] != $fromIdCard['ID_CARD'])) {
                $this->addError($attribute, '奖金转奖金只能在同一身份证下进行');
                return null;
            }
        }*/
        //奖金转现金限一周一次
        /*if ($this->type == self::BONUS_TO_BALANCE) {
            if (Transfer::hasThisWeekTransfer(\Yii::$app->user->id)) {
                $this->addError($attribute, '转账失败，每周只可以转账一次');
                return null;
            }
        }*/
    }

    /**
     * 校验申请金额是否小于当前余额并符合配置中的设置
     * @param $attribute
     * @return null
     */
    public function isAmount($attribute) {
        if(!$this->_fromUserInfo){
            $this->addError($attribute, 'Member info has not been verified'); // 会员信息未验证通过
            return null;
        }
        if ($this->amount <= 0) {
            $this->addError($attribute, 'The transfer amount must be greater than 0'); // 转账金额必须大于0
        }
        if ((int)$this->amount!=$this->amount) {
            $this->addError('scenario', 'The transfer amount must be a round number'); // 转账金额必须是整数
        }
        $minAmount = $this->_transferConfig['outMin'];
        if ($this->amount < $minAmount) {
            $this->addError($attribute, 'The transfer amount is lower than the transfer limit'); // 转账金额低于转账下限
        }
        $maxAmount = $this->_transferConfig['outMax'];
        if ($maxAmount && $this->amount > $maxAmount) {
            $this->addError($attribute, 'The transfer amount is higher than the transfer limit'); // 转账金额高于转账上限
        }
        //周转账上限
        if($this->_transferConfig['weekMax']!=0){
            if($this->amount+Transfer::weekTransfer($this->_fromUserInfo['ID'])>$this->_transferConfig['weekMax']){
                $this->addError($attribute, 'The working book limit is exceeded'); // 超出周转账上限
            }
        }
        //月转账上限
        if($this->_transferConfig['monthMax']!=0){
            if($this->amount+Transfer::monthTransfer($this->_fromUserInfo['ID'])>$this->_transferConfig['weekMax']){
                $this->addError($attribute, 'Exceed the monthly transfer limit'); // 超出月转账上限
            }
        }

        // 获取当前用户的可用金额
        if( $this->type == self::BALANCE_TO_BALANCE ) {
            $haveBalance = Cash::getAvailableBalance($this->_fromUserInfo['ID']);
        }else {
            $haveBalance = Balance::getAvailableBalance($this->_fromUserInfo['ID']);
        }
        if ($this->amount > $haveBalance) {
            $this->addError($attribute, 'The transfer amount must be less than your available balance'); // 转账金额必须小于自己的可用余额
        }
        // 转账比例
        if ($this->type == self::BONUS_TO_BALANCE) {
            $isCanTransferProp = Cache::getSystemConfig()['isCanTransferProp']['VALUE'];
            if ($isCanTransferProp == 1) {
                $maxAmount = Tool::formatPrice($this->_fromUserInfo['TRANSFER_PROP'] * Balance::getAvailableBalance($this->_fromUserInfo['ID']) * 0.01);
                if ($this->amount > $maxAmount) {
                    $this->addError($attribute, 'The transfer amount exceeds the transfer ratio limit'); // 转账金额超出转账比例限额
                }
            }
        }

        //手续费
        if($this->_transferConfig['fee']!=0){
            $fee = Tool::formatPrice($this->amount * ($this->_transferConfig['fee']) * 0.01);
            if($this->_transferConfig['feeMin']!=0&&$fee<$this->_transferConfig['feeMin']){
                $fee = $this->_transferConfig['feeMin'];
            }
            if($this->_transferConfig['feeMax']!=0&&$fee>$this->_transferConfig['feeMax']){
                $fee = $this->_transferConfig['feeMax'];
            }
            $this->_fee = $fee;
        }
    }

    /**
     * 转账类型判断
     * @param $attribute
     */
    public function isType($attribute) {
        if (!in_array($this->type, self::allowTransferType)) {
            $this->addError($attribute, 'Types of transfers that are not allowed'); // 不允许的转账类型
        }
        //获取转账参数
        if(!$this->_transferConfig = Json::decode(Cache::getSystemConfig()['allowWallet']['VALUE'])[$this->type-1]){
            $this->addError($attribute, 'Wrong type of transfer'); // 错误的转账类型
        }
        if(!$this->_transferConfig['isOpen']){
            $this->addError($attribute, 'Type of transfer that is not available'); // 不可用的转账类型
        }
    }

    /**
     * 校验支付密码
     * @param $attribute
     * @param $params
     */
    public function validatePassword($attribute, $params) {
        if (!User::validatePayPassword($this->_fromUserInfo['ID'], $this->payPassword)) {
            $this->addError($attribute, 'The payment password is incorrect');//支付密码不正确
        }
    }

    public function validateCode($attribute, $params) {
        $uid = \Yii::$app->user->id;
        $redisCode = \Yii::$app->redis->getset('transferCode_'.$uid,'');
        \Yii::$app->redis->del('transferCode_'.$uid);
        if ($this->transferCode!=$redisCode) {
            $this->addError($attribute, 'Transfer verification failed '.$redisCode); // 转账校验失败
        }
    }
    /**
     * 生成随机数
     * @param $length
     * @param int $numeric
     * @return string
     */
    public function random($length, $numeric = 0) {
        $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
        $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
        $hash = '';
        $max = strlen($seed) - 1;
        for ($i = 0; $i < $length; $i++) {
            $hash .= $seed[mt_rand(0, $max)];
        }
        return $hash;
    }

    /**
     * 转账
     * @return Transfer|null
     * @throws \Exception
     */
    public function transfer() {
        if (!$this->validate()) {
            return null;
        }
        if ($this->_fromUserInfo['ID']==$this->_toUserInfo['ID']){
            throw new \Exception(Yii::t('app', 'notAllowedToTransferToYourself'));
        }
        $fromData = Balance::getLogData($this->_fromUserInfo['ID']);
        $toData = Balance::getLogData($this->_toUserInfo['ID']);
        $this->userOperateLogger->saveBeforeContent=array_merge($fromData,$toData);

        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            $amount = Tool::formatPrice($this->amount - $this->_fee);
            // 转账记录
            $period = Period::instance();
            $model = new Transfer();
            $model->ID = SnowFake::instance()->generateId();
            $model->TRANSFER_SN = Transfer::generateSN();
            $model->OUT_UID = $this->_fromUserInfo['ID'];
            $model->LAST_OUT_USER_NAME = $this->_fromUserInfo['USER_NAME'];
            $model->LAST_OUT_REAL_NAME = $this->_fromUserInfo['REAL_NAME'];
            $model->LAST_OUT_DEC_LV = $this->_fromUserInfo['DEC_LV'];
            $model->LAST_OUT_DEC_ROLE_ID = $this->_fromUserInfo['DEC_ROLE_ID'];
            $model->OUT_WALLET = $this->_transferConfig['out'];
            $model->LAST_OUT_SYSTEM_ID = $this->_fromUserInfo['SYSTEM_ID'] ? $this->_fromUserInfo['SYSTEM_ID'] : '';
            $model->IN_UID = $this->_toUserInfo['ID'];
            $model->LAST_IN_USER_NAME = $this->_toUserInfo['USER_NAME'];
            $model->LAST_IN_REAL_NAME = $this->_toUserInfo['REAL_NAME'];
            $model->LAST_IN_DEC_LV = $this->_toUserInfo['DEC_LV'];
            $model->IN_WALLET = $this->_transferConfig['in'];
            $model->LAST_IN_SYSTEM_ID = $this->_toUserInfo['SYSTEM_ID'] ? $this->_toUserInfo['SYSTEM_ID'] : '';
            $model->ORI_AMOUNT = $this->amount;
            $model->FEE = $this->_fee;
            $model->AMOUNT = $amount;
            $model->REMARK = $this->remark;
            $model->PERIOD_NUM = $period->getNowPeriodNum();
            $model->CALC_MONTH = $period->getNowYearMonth();
            $model->CREATED_AT = Date::nowTime();
            if (!$model->save()) {
                throw new Exception(Form::formatErrorsForApi($model->getErrors()));
            }
            if ($this->type == self::BONUS_TO_BALANCE) {
                // 会员金额减少
                Balance::changeUserBonus($this->_fromUserInfo['ID'], 'bonus', -abs($this->amount), ['TRANSFER_SN' => $model->TRANSFER_SN, 'DEAL_TYPE_ID' => DealType::TRANSFER_OUT, 'REMARK' => 'To:' . $this->_toUserInfo['USER_NAME'] . '，' . $this->remark]);
                Cash::changeUserCash($this->_toUserInfo['ID'], 'CASH', abs($amount), ['TRANSFER_SN' => $model->TRANSFER_SN,'DEAL_TYPE_ID' => DealType::TRANSFER_IN, 'REMARK' => 'From:' . $this->_fromUserInfo['USER_NAME'] . '，' . $this->remark]);
            } elseif($this->type == self::BONUS_TO_BONUS) {
                // 会员金额减少
                Balance::changeUserBonus($this->_fromUserInfo['ID'], 'bonus', -abs($this->amount), ['TRANSFER_SN' => $model->TRANSFER_SN, 'DEAL_TYPE_ID' => DealType::TRANSFER_OUT, 'REMARK' => 'To:' . $this->_toUserInfo['USER_NAME'] . '，' . $this->remark]);
                Balance::changeUserBonus($this->_toUserInfo['ID'], 'bonus', abs($amount), ['TRANSFER_SN' => $model->TRANSFER_SN, 'DEAL_TYPE_ID' => DealType::TRANSFER_IN, 'REMARK' => 'From:' . $this->_fromUserInfo['USER_NAME'] . '，' . $this->remark]);
            }else if ($this->type == self::BALANCE_TO_BALANCE) {
                // 会员金额减少
                Cash::changeUserCash($this->_fromUserInfo['ID'], 'CASH', -abs($this->amount), ['TRANSFER_SN' => $model->TRANSFER_SN,'DEAL_TYPE_ID' => DealType::TRANSFER_OUT, 'REMARK' => 'To:' . $this->_toUserInfo['USER_NAME'] . '，' . $this->remark]);
                Cash::changeUserCash($this->_toUserInfo['ID'], 'CASH', abs($amount), ['TRANSFER_SN' => $model->TRANSFER_SN,'DEAL_TYPE_ID' => DealType::TRANSFER_IN, 'REMARK' => 'From:' . $this->_fromUserInfo['USER_NAME'] . '，' . $this->remark]);
            }else {
                throw new \Exception(Yii::t('app', 'wrongTransactionType'));
            }

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

        $fromData = Balance::getLogData($this->_fromUserInfo['ID']);
        $toData = Balance::getLogData($this->_toUserInfo['ID']);
        $this->userOperateLogger->saveAfterContent=array_merge($fromData,$toData);
        unset($fromData,$toData);
        $this->userOperateLogger->clean()->save([
            'optType' => '会员转账',
            'userId' => \Yii::$app->user->id,
            'userName' => Info::getUserNameByUserId(\Yii::$app->user->id),
            'remark' => $this->remark,
        ]);
        return $model;
    }


}
