<?php

namespace common\models\forms;

use common\components\Model;
use common\helpers\Cache;
use common\helpers\Date;
use common\helpers\Form;
use common\helpers\Tool;
use common\helpers\user\Cash;
use common\helpers\user\Info;
use common\models\Recharge;
use common\models\RechargeLog;
use common\models\UserInfo;
use yii\base\Exception;

/**
 * Login form
 */
class RechargeForm extends Model {
    public $selectedIds;
    public $auditStatus;
    public $createRemark;

    public $userName;
    public $applyAmount;
    public $openBank;
    public $bankAddress;
    public $bankNo;
//    public $bankProvince;
//    public $bankCity;
//    public $bankCounty;

    public $sn;
    public $amount;
    public $bankRealName;

    private $_userId;

    public $id;
    public $rechargeType;

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['userName', 'idCard', 'applyAmount', 'auditStatus', 'remark', 'selectedIds', 'sn','amount', 'bankRealName', 'bankNo','rechargeType'], 'trim'],
            [['selectedIds', 'auditStatus', 'userName','applyAmount','openBank','bankNo'/*,'bankAddress'*/], 'required'],
            [['selectedIds'], 'exist', 'targetClass' => Recharge::class, 'targetAttribute' => 'ID', 'message' => 'Recharge does not exist'], // 充值申请不存在
            [['userName'], 'exist', 'targetClass' => UserInfo::class, 'targetAttribute' => 'USER_NAME', 'message' => 'Member does not exist'],// 会员不存在
            [['applyAmount'], 'price'],
            [['applyAmount'], 'isApplyAmount'],
            [['applyAmount'], 'number', 'max' => 10000000000, 'min' => 1],
            [['selectedIds'], 'isSelected'],
            [['id'], 'number'],
            ['rechargeType', 'string', 'max' => 50], // 限制长度
            ['rechargeType', 'in', 'range' => ['Cash', 'Credit Card', 'Direct Banking']],
            //[['sn'], 'isSn'],
        ];
    }

    /**
     * 指定场景
     * @return array
     */
    public function scenarios() {
        $parentScenarios = parent::scenarios();
        $customScenarios = [
            'addByAdmin' => ['userName', 'applyAmount'],
            'addByUser' => ['applyAmount','openBank','bankNo','bankAddress','rechargeType'/*,'currency'*/],
            'updateByUser' => ['id','applyAmount','openBank','bankNo','bankAddress','rechargeType'/*,'currency'*/],
            'statusByAdmin' => ['selectedIds', 'auditStatus', 'createRemark'],
            'updateByAdmin' => ['id', 'rechargeType'],
        ];
        return array_merge($parentScenarios, $customScenarios);
    }

    /**
     * @return array
     */
    public function attributeLabels() {
        return [
            'selectedIds' => 'RechargeID',// 充值申请ID
            'userName' => 'Member code',// 会员编号
            'applyAmount' => 'Apply Amount', // 申请充值的金额
            'openBank' => 'Bank name',// 汇款银行
            'bankNo' => 'Payment Reference', // 汇款账号
//            'bankAddress' => '银行支行',
//            'bankProvince' => '银行省',
//            'bankCity' => '银行市',
//            'bankCounty' => '银行县',
        ];
    }

    /**
     * 校验申请金额是否小于当前余额并符合配置中的设置
     * @param $attribute
     * @return bool
     */
    public function isApplyAmount($attribute) {
        if ($this->applyAmount <= 0) {
            $this->addError('scenario', 'The recharge amount must be greater than 0'); // 充值金额必须大于0
        }
        if ((int)($this->applyAmount)!=$this->applyAmount) {
            $this->addError('scenario', 'The recharge amount must be an integer');// 充值金额必须是整数
        }
        if ($this->scenario == 'addByUser') {
            $this->_userId = \Yii::$app->user->id;
        } elseif ($this->scenario == 'addByAdmin') {
            $userInfo = UserInfo::findOneAsArray(['USER_NAME' => $this->userName]);
            if (!$userInfo) {
                $this->addError('scenario', $this->userName . 'Member does not exist');// 会员不存在
            }else{
                $this->_userId = $userInfo['USER_ID'];
            }
        } elseif ($this->scenario == 'updateByUser') {
            $this->_userId = \Yii::$app->user->id;
        } else {
            $this->addError($attribute, 'Scenes does not exist'); // 场景不存在
            return false;
        }
    }

    /**
     * 批量数据
     * @param $attributes
     */
    public function isSelected($attributes) {
        if (!$this->selectedIds) {
            $this->addError($attributes, 'A piece of data must be selected'); // 必须选择一条数据
        }
//        if (!is_array($this->selectedIds)) {
//            $this->selectedIds = [$this->selectedIds];
//        }
    }

    /**
     * 判断信息是否一致
     * @param $attribute
     * @throws Exception
     */
    public function isSn($attribute) {
        $sn = $this->sn;
        if (!$oneWithdraw = Recharge::findOneAsArray('SN=:SN AND AUDIT_STATUS=:AUDIT_STATUS', [':SN' => $sn, ':AUDIT_STATUS' => Recharge::STATUS_AUDITED])) {
            $this->addError($attribute, '不存在充值流水号为' . $sn . '的已审核记录');
        }
        if ($oneWithdraw) {
            $info = Info::baseInfo($oneWithdraw['USER_ID']);
            if ($this->userName != $info['USER_NAME']) {
                $this->addError($attribute, 'Excel中充值流水号' . $sn . '的用户名' . $this->userName . '与系统中的信息【' . $info['USER_NAME'] . '】不一致');
            }
            if ($this->amount != $oneWithdraw['AMOUNT']) {
                $this->addError($attribute, 'Excel中充值流水号' . $sn . '的充值金额' . $this->amount . '与系统中的信息【' . $oneWithdraw['AMOUNT'] . '】不一致');
            }
            if ($this->bankRealName != $oneWithdraw['REAL_NAME']) {
                $this->addError($attribute, 'Excel中充值流水号' . $sn . '的实时开户名' . $this->bankRealName . '与系统中的信息【' . $oneWithdraw['REAL_NAME'] . '】不一致');
            }
            if ($this->bankNo != $oneWithdraw['BANK_NO']) {
                $this->addError($attribute, 'Excel中充值流水号' . $sn . '的实时银行账户' . $this->bankNo . '与系统中的信息【' . $oneWithdraw['BANK_NO'] . '】不一致');
            }
        }
    }

    /**
     * 管理员充值
     * @return null|string
     * @throws \yii\db\Exception
     */
    public function recharge() {
        if (!$this->validate()) {
            return false;
        }
        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            Cash::changeUserCash($this->_userId, 'CASH', $this->applyAmount, ['REMARK' => 'Background administrator recharge']);

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


    /**
     * 添加充值申请
     * @return null|string
     * @throws \yii\db\Exception
     */
    public function add() {
        if (!$this->validate()) {
            return false;
        }
        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            $nowTime = Date::nowTime();
            $period = Recharge::getPeriod($nowTime);
            //增加记录
            $userInfo = Info::baseInfo($this->_userId);

            $rechargeModel = new Recharge();
            $rechargeModel->SN = $this->_generateSn();
            $rechargeModel->USER_ID = $this->_userId;
            $rechargeModel->REAL_NAME = Info::getUserRealNameByUserId($this->_userId);
            $rechargeModel->ID_CARD = $userInfo['ID_CARD'];
            $rechargeModel->RECHARGE_PERIOD_NUM = $period['nowPeriodNum'];
            $rechargeModel->RECHARGE_YEAR = $period['nowYear'];
            $rechargeModel->RECHARGE_MONTH = $period['nowMonth'];
            $rechargeModel->AMOUNT = $this->applyAmount;
            $rechargeModel->OPEN_BANK = $this->openBank;
            $rechargeModel->BANK_ADDRESS = $this->bankAddress;
            $rechargeModel->BANK_NO = $this->bankNo;
            $rechargeModel->TYPE = $this->rechargeType;
//            $rechargeModel->BANK_PROVINCE = $this->bankProvince ?? 0;
//            $rechargeModel->BANK_CITY = $this->bankCity ?? 0;
//            $rechargeModel->BANK_COUNTY = $this->bankCounty ?? 0;
            $rechargeModel->P_MONTH = Date::ociToDate($period['yearMonth'], Date::OCI_TIME_FORMAT_SHORT_MONTH);
            $rechargeModel->AUDIT_STATUS = Recharge::STATUS_APPLIED;
            $rechargeModel->CREATED_AT = $nowTime;
            if (!$rechargeModel->save()) {
                throw new Exception(Form::formatErrorsForApi($rechargeModel->getErrors()));
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->addError('add', $e->getMessage());
            return false;
        }
        return $rechargeModel;
    }

    /**
     * 更新充值申请
     * @return null|string
     * @throws \yii\db\Exception
     */
    public function update() {
        if (!$this->validate()) {
            return false;
        }
        if(!$this->id){
            return false;
        }
        $rechargeModel = Recharge::findOne(['ID' => $this->id]);
        if(in_array($rechargeModel->AUDIT_STATUS,[Recharge::STATUS_PROCESSING,Recharge::STATUS_SUCCESS,Recharge::STATUS_REJECT])){
            $this->addError('scenario', 'This status cannot be modified');
            return false;
        }
        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            $nowTime = Date::nowTime();
            $rechargeLogModel = new RechargeLog();
            $rechargeLogModel->SN = $this->_generateSn();
            $rechargeLogModel->USER_ID = $rechargeModel->USER_ID;
            $rechargeLogModel->REAL_NAME = $rechargeModel->REAL_NAME;
            $rechargeLogModel->ID_CARD = $rechargeModel->ID_CARD;
            $rechargeLogModel->RECHARGE_PERIOD_NUM = $rechargeModel->RECHARGE_PERIOD_NUM;
            $rechargeLogModel->RECHARGE_YEAR = $rechargeModel->RECHARGE_YEAR;
            $rechargeLogModel->RECHARGE_MONTH =$rechargeModel->RECHARGE_MONTH;
            $rechargeLogModel->AMOUNT = $rechargeModel->AMOUNT;
            $rechargeLogModel->UPDATE_AMOUNT = $this->applyAmount;
            $rechargeLogModel->OPEN_BANK = $rechargeModel->OPEN_BANK;
            $rechargeLogModel->UPDATE_OPEN_BANK = $this->openBank;
            $rechargeLogModel->BANK_ADDRESS = $rechargeModel->BANK_ADDRESS;
            $rechargeLogModel->UPDATE_BANK_ADDRESS = $this->bankAddress;
            $rechargeLogModel->BANK_NO = $rechargeModel->BANK_NO;
            $rechargeLogModel->UPDATE_BANK_NO = $this->bankNo;
            $rechargeLogModel->P_MONTH = $rechargeModel->P_MONTH;
            $rechargeLogModel->AUDIT_STATUS = $rechargeModel->AUDIT_STATUS;
            $rechargeLogModel->TYPE = $rechargeModel->TYPE;
            $rechargeLogModel->CREATED_AT = $nowTime;
            if (!$rechargeLogModel->save()) {
                throw new Exception(Form::formatErrorsForApi($rechargeLogModel->getErrors()));
            }

            $rechargeModel->AMOUNT = $this->applyAmount;
            $rechargeModel->OPEN_BANK = $this->openBank;
            $rechargeModel->BANK_ADDRESS = $this->bankAddress;
            $rechargeModel->BANK_NO = $this->bankNo;
//            $rechargeModel->UPDATED_AT = $nowTime;
            $rechargeModel->TYPE = $this->rechargeType;
            if (!$rechargeModel->save()) {
                throw new Exception(Form::formatErrorsForApi($rechargeModel->getErrors()));
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->addError('update', $e->getMessage());
            return false;
        }
        return $rechargeModel;
    }

    /**
     * 更新充值申请
     * @return null|string
     * @throws \yii\db\Exception
     */
    public function updateType() {
        if (!$this->validate(['id', 'rechargeType'])) {
            return false;
        }
        if(!$this->id){
            return false;
        }
        $rechargeModel = Recharge::findOne(['ID' => $this->id]);
//        if(in_array($rechargeModel->AUDIT_STATUS,[Recharge::STATUS_PROCESSING,Recharge::STATUS_SUCCESS,Recharge::STATUS_REJECT])){
//            $this->addError('scenario', 'This status cannot be modified');
//            return false;
//        }
        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            $nowTime = Date::nowTime();
            $rechargeLogModel = new RechargeLog();
            $rechargeLogModel->SN = $this->_generateSn();
            $rechargeLogModel->USER_ID = $rechargeModel->USER_ID;
            $rechargeLogModel->REAL_NAME = $rechargeModel->REAL_NAME;
            $rechargeLogModel->ID_CARD = $rechargeModel->ID_CARD;
            $rechargeLogModel->RECHARGE_PERIOD_NUM = $rechargeModel->RECHARGE_PERIOD_NUM;
            $rechargeLogModel->RECHARGE_YEAR = $rechargeModel->RECHARGE_YEAR;
            $rechargeLogModel->RECHARGE_MONTH =$rechargeModel->RECHARGE_MONTH;
            $rechargeLogModel->AMOUNT = $rechargeModel->AMOUNT;
            $rechargeLogModel->UPDATE_AMOUNT = $rechargeModel->AMOUNT;
            $rechargeLogModel->OPEN_BANK = $rechargeModel->OPEN_BANK;
            $rechargeLogModel->UPDATE_OPEN_BANK = $rechargeModel->OPEN_BANK;
            $rechargeLogModel->BANK_ADDRESS = $rechargeModel->BANK_ADDRESS;
            $rechargeLogModel->UPDATE_BANK_ADDRESS = $rechargeModel->BANK_ADDRESS;
            $rechargeLogModel->BANK_NO = $rechargeModel->BANK_NO;
            $rechargeLogModel->UPDATE_BANK_NO = $rechargeModel->BANK_NO;
            $rechargeLogModel->P_MONTH = $rechargeModel->P_MONTH;
            $rechargeLogModel->AUDIT_STATUS = $rechargeModel->AUDIT_STATUS;
            $rechargeLogModel->TYPE = $rechargeModel->TYPE;
            $rechargeLogModel->CREATED_AT = $nowTime;
            if (!$rechargeLogModel->save()) {
                throw new Exception(Form::formatErrorsForApi($rechargeLogModel->getErrors()));
            }

            $rechargeModel->TYPE = $this->rechargeType;
            if (!$rechargeModel->save()) {
                throw new Exception(Form::formatErrorsForApi($rechargeModel->getErrors()));
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->addError('updateType', $e->getMessage());
            return false;
        }
        return $rechargeModel;
    }

    /**
     * 生成流水号
     * @return string
     */
    private function _generateSn() {
        return 'CZ' . Date::today('Ymd') . $this->_random(10, 1);
    }

    /**
     * 生成随机数
     *
     * @param $length
     * @param int $numeric
     * @return string
     */
    private 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 null|static
     * @throws \yii\db\Exception
     */
    public function changeStatus() {
        if (!$this->validate()) {
            return null;
        }
        $logs = [];
        $db = \Yii::$app->db;
        $transaction = $db->beginTransaction();
        try {
            $oneRecharge = Recharge::findOne(['ID' => $this->selectedIds]);
            //判断状态
            if (($msg = Recharge::chkAuditStatus($oneRecharge->SN, $oneRecharge->AUDIT_STATUS, $this->auditStatus)) != '') {
                throw new Exception($msg);
            }
            //待审核->已审核 修改会员现金钱包
            if ($this->auditStatus == Recharge::STATUS_AUDITED) {
                Cash::changeUserCash($oneRecharge->USER_ID, 'CASH', abs($oneRecharge->AMOUNT), ['REMARK' => 'Review member recharge application']);
            }
            $oneRecharge->REMARK = $this->createRemark ?? '';
            $oneRecharge->AUDIT_ADMIN = \Yii::$app->user->id;
            $oneRecharge->AUDIT_STATUS = $this->auditStatus;
            $oneRecharge->AUDITED_AT = Date::nowTime();
            if (!$oneRecharge->save()) {
                throw new Exception(Form::formatErrorsForApi($oneRecharge->getErrors()));
            }
            $logs[$this->selectedIds] = $oneRecharge->SN;

            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->addError('auditStatus', $e->getMessage());
            return null;
        }
        return ['logs' => $logs, 'status' => $this->auditStatus];
    }

}
