<?php
/**
 * Created by PhpStorm.
 * User: leo
 * Date: 2018/10/30
 * Time: 下午3:19
 */

namespace common\helpers\user;

use common\helpers\Date;
use common\helpers\Form;
use common\libs\lock\RedisLock;
use common\models\FlowWallet;
use common\models\Period;
use common\models\UserWallet;
use yii\base\Exception;
use yii\db\Expression;

class Cash {
    const INCR_REDUCE = 0;      // 减少
    const INCR_ADD = 1;         // 增加
    const INCR_FREEZE = 2;      // 冻结
    const INCR_UNFREEZE = 3;    // 解冻

    const CASH_BALANCE_LOCK_KEY = 'Cash';

    /**
     * 获取当前可用余额
     * @param $userId
     * @return int|mixed
     */
    public static function getAvailableBalance($userId) {
        $oneData = UserWallet::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
        if ($oneData) {
            return $oneData['CASH'];
        } else {
            return 0;
        }
    }

    /**
     * 改变会员的现金余额
     * @param $userId
     * @param $type
     * @param $amount
     * @param array $params
     * @param bool $allowMinus
     * @return bool
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public static function changeUserCash($userId, $type='CASH', $amount, $params = [], $allowMinus = false) {
        if ($amount == 0) return true;
        $period = Period::instance();
        if (!isset($params['PERIOD_NUM'])) {
            $periodNum = $period->getNowPeriodNum();
        } else {
            $periodNum = $params['PERIOD_NUM'];
        }
        $calcYearMonth = $period->getYearMonth($periodNum);
        // redis加锁（防止并发余额数值不准确出错）
        switch ($type) {
            case 'CASH':
                $lockKey = self::CASH_BALANCE_LOCK_KEY . $userId;
                break;
            default:
                throw new Exception('流水类型错误');
        }
        if (RedisLock::instance()->lock($lockKey)) {
            // 改变发奖
            $paramData = [];
            $oneUserBonusModel = UserWallet::findOne(['USER_ID' => $userId]);
            if ($oneUserBonusModel) {
                $paramData[$type] = new Expression($type.' + '.$amount);

                $oneUserBonusModel->$type += $amount;
                if ($oneUserBonusModel->$type < 0) {
                    RedisLock::instance()->unlock($lockKey);
                    throw new Exception('金额不足');
                }
                UserWallet::updateAll($paramData, 'USER_ID=:USER_ID', [':USER_ID' => $userId]);

            } else {
                $paramData = [
                    'USER_ID'=>$userId,
                    $type=>$amount,
                    'UPDATED_AT'=>Date::nowTime()
                ];
                UserWallet::insertOne($paramData);

//                $oneUserBonusModel = new UserWallet();
//                $oneUserBonusModel->USER_ID = $userId;
//                $oneUserBonusModel->$type = $amount;
//                $oneUserBonusModel->UPDATED_AT = Date::nowTime();
//                if (!$oneUserBonusModel->save()) {
//                    throw new \yii\db\Exception(Form::formatErrorsForApi($oneUserBonusModel->getErrors()));
//                }
            }

            unset($oneUserBonusModel,$paramData);
            // 获取发放完成的奖金信息
            $oneUserBonus = UserWallet::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
            // 记录流水
            $flowInsertData = [
                'USER_ID' => $userId,
                'CALC_ID' => $params['CALC_ID'] ?? null,
                'AMOUNT' => $amount,
                'TOTAL' => $oneUserBonus[$type],
                'IS_INCR' => $amount > 0 ? FlowWallet::INCR_ADD : FlowWallet::INCR_REDUCE,
                'REMARK' => $params['REMARK'] ?? null,
                'PERIOD_NUM' => $params['PERIOD_NUM'] ?? $periodNum,
                'CALC_MONTH' => $calcYearMonth,
                'P_MONTH' => Date::ociToDate(),
                'CREATED_AT' => $params['TIME'] ?? Date::nowTime(),
                'ADMIN_NAME' => $params['ADMIN_NAME'] ?? 'system',
                'SORT' => $params['SORT'] ?? 0,
                'TRANSFER_SN' => $params['TRANSFER_SN'] ?? '',
            ];
            if (strtolower($type) == 'cash') FlowWallet::insertOne($flowInsertData);
            unset($flowInsertData);
            RedisLock::instance()->unlock($lockKey);
        } else {
            throw new Exception('流水产生错误');
        }
        return true;
    }

    /**
     * 清空会员现金所有流水
     * @param $userId
     * @param array $params
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public static function clearAllCash($userId, $params = []) {
        // 先查找会员的全部余额
        $userWallet = UserWallet::findOne(['USER_ID' => $userId]);
        // 如果没有会员余额数据，新建余额数据
        if (!$userWallet) {
            UserWallet::insertOne(['USER_ID' => $userId, 'CREATED_AT' => Date::nowTime()]);
        } else {
            $period = Period::instance();
            $field = 'CASH';
            if ($userWallet[$field]<=0) return;
            $flowInsertData = [
                'USER_ID' => $userId,
                'CALC_ID' => $params['CALC_ID'] ?? null,
                'AMOUNT' => -$userWallet[$field],
                'TOTAL' => 0,
                'IS_INCR' => FlowWallet::INCR_REDUCE,
                'REMARK' => $params['REMARK'] ?? null,
                'PERIOD_NUM' => $params['PERIOD_NUM'] ?? $period->getNowPeriodNum(),
                'CALC_MONTH' => $period->getNowYearMonth(),
                'P_MONTH' => Date::ociToDate(),
                'CREATED_AT' => $params['TIME'] ?? Date::nowTime(),
                'ADMIN_NAME' => $params['ADMIN_NAME'] ?? 'system',
                'SORT' => $params['SORT'] ?? 0,
                'TRANSFER_SN' => $params['TRANSFER_SN'] ?? '',
            ];
            // 流水
            if (strtolower($field) == 'cash') FlowWallet::insertOne($flowInsertData);

            // 清空
            $userWallet->CASH = 0;
            if (!$userWallet->save()) {
                throw new Exception(Form::formatErrorsForApi($userWallet->getErrors()));
            }
        }
        FlowWallet::updateAll(['DELETED' => 1, 'DELETED_AT' => Date::nowTime()], 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
    }

    /**
     * 是否存在现金余额
     * @param $userId
     * @return bool
     */
    public static function hasCash($userId) {
        $userWallet = UserWallet::findOne(['USER_ID' => $userId]);
        if (!$userWallet) {
            return false;
        }
        if (isset($userWallet['CASH']) && $userWallet['CASH'] > 0) {
            return true;
        }
    }

    /**
     * 获取金额用于日志
     * @param $userId
     * @return array
     */
    public static function getLogData($userId){
        $userWallet = UserWallet::findOne(['USER_ID' => $userId]);
        $userName = Info::getUserNameByUserId($userId);
        $data = [];
        $data[$userId]['label'] = $userName.'余额';
        $data[$userId]['value'] = '奖金'.self::getAvailableBalance($userId).',现金'.$userWallet['CASH'];
        return $data;
    }
}