<?php
/**
 * Payments.php UTF-8
 *
 *
 * @date    : 2017/5/2 14:50
 *
 * @license 这不是一个自由软件,未经授权不许任何使用和传播。
 * @author  : wuyonghong <wyh@huosdk.com>
 * @version : HUOSDK 7.0
 */

namespace huoMpay;

use huo\controller\common\Base;
use huo\controller\common\HuoSession;
use huo\controller\pay\Notify;
use huo\controller\pay\Sdk;
use huo\controller\pay\SdkOrderCache;
use huolib\constant\OrderConst;
use huolib\constant\PaywayConst;
use huolib\status\OrderStatus;
use huolib\tool\StrUtils;
use huomp\controller\game\GameMini;
use huomp\model\wallet\MgmLogModel;
use huomp\model\wallet\MidasGmMemModel;
use think\Log;

class Payments extends Base {
    const MGM_QUERY   = 1; /* 1 查询 */
    const MGM_PAY     = 2; /* 2 扣费 */
    const MGM_PRESENT = 3; /* 3 赠送  */
    const MGM_CANCEL  = 4; /* 4 取消支付 */
    /**
     * 获取余额并且支付
     *
     * @param int    $mem_id   玩家ID
     * @param string $order_id 订单ID
     *
     * @return array
     */
    public function getBalanceAndPay($mem_id, $order_id) {
        if (empty($order_id)) {
            $_code = OrderStatus::ORDER_ID_EMPTY;

            return $this->huoError($_code, OrderStatus::getMsg($_code));
        }
        $_soc_class = SdkOrderCache::ins();
        $_order_data = $_soc_class->getInfoByOrderId($order_id);
        if (empty($_order_data)) {
            $_code = OrderStatus::ORDER_ID_ERROR;

            return $this->huoError($_code, OrderStatus::getMsg($_code));
        }
        if ($mem_id != $_order_data['mem_id']) {
            $_code = OrderStatus::ORDER_NOT_EXISTS;

            return $this->huoError($_code, OrderStatus::getMsg($_code));
        }
        $mem_id = $_order_data['mem_id'];
        $_rdata['status'] = $_order_data['status'];
        $_rdata['cp_status'] = $_order_data['cp_status'];
        if (OrderConst::CP_STATUS_SUC != $_order_data['cp_status']
            && OrderConst::PAY_STATUS_SUC == $_order_data['status']) {
            $_rs = (new Notify())->notify($order_id);
            if (OrderStatus::NO_ERROR == $_rs['code']) {
                $_rdata['status'] = OrderConst::PAY_STATUS_SUC;
                $_rdata['cp_status'] = OrderConst::CP_STATUS_SUC;
            }
            $_code = OrderStatus::NO_ERROR;

            return $this->huoSuccess($_code, OrderStatus::getMsg($_code), $_rdata);
        }
        /* 获取余额 */
        $_rs = $this->midasGetBalance($mem_id, $order_id);
        if (OrderStatus::NO_ERROR != $_rs['code']) {
            return $this->huoError($_rs['code'], $_rs['msg']);
        }
        $_data = $_rs['data'];
        $_mgm_model = (new MidasGmMemModel());
        $_mgm_data = $_mgm_model->getDataOrInsert($mem_id, $_order_data['app_id']);
        $_diff_gm_cnt = StrUtils::formatNumber($_data['save_amt'] - $_mgm_data['m_save_amt']);
        /* 数量大于等于充值金额 */
        $_product_cnt = StrUtils::formatNumber($_order_data['product_cnt']);
        /* 变化的游戏币必须币充值的游戏币多 */
        if ($_diff_gm_cnt < $_product_cnt) {
            $_code = OrderStatus::NOTIFY_AMOUNT_ERROR;
            Log::write(
                "func=".__FUNCTION__."&class=".__CLASS__."&step1&code=".$_code.'&data.'
                .http_build_query($_data).'&order_data='.http_build_query($_order_data).'&mgm_data='.http_build_query(
                    $_mgm_data
                ).'&diff_gm_cnt='.$_diff_gm_cnt.'&product_cnt='.$_product_cnt.'&rs='.json_encode($_rs),
                LOG::ERROR
            );

            return $this->huoError($_code, OrderStatus::getMsg($_code));
        }
        /* 扣除所有游戏币 */
        /* 获取余额 */
        $_rs = $this->midasPay($mem_id, $order_id);
        if (OrderStatus::NO_ERROR != $_rs['code'] && 90012 != $_rs['code']) {
            return $this->huoError($_rs['code'], $_rs['msg']);
        }
        $_rs = (new Notify())->payNotify(
            $_order_data['product_id'], $order_id, '', $_order_data['amount'], $_order_data['payway']
        );
        if (false == $_rs) {
            $_code = OrderStatus::INNER_ERROR;

            return $this->huoError($_code, OrderStatus::getMsg($_code));
        }
        /* 更新米大师游戏币 */
        $_mgm_data['m_balance'] = $_data['balance'] - $_product_cnt;
        $_mgm_data['m_gen_balance'] = $_data['gen_balance'];
        $_mgm_data['m_save_amt'] += $_product_cnt;
        $_mgm_data['m_save_sum'] = $_data['save_sum'];
        $_mgm_data['m_cost_sum'] = $_data['cost_sum'];
        $_mgm_data['m_present_sum'] = $_data['present_sum'];
        $_mgm_data['sum_money'] += $_order_data['amount'];
        $_mgm_data['total'] += $_product_cnt;
        $_mgm_data['remain'] += $_mgm_data['m_balance'];
        $_mgm_model->updateData($_mgm_data, $_mgm_data['id']);
        /* 插入每条记录 */
// TODO: wuyonghong 2018/8/16 插入log记录
        /* 从订单中获取状态 */
        $_statues = (new Sdk())->getStatus($order_id);
        if (false == $_statues) {
            $_code = OrderStatus::ORDER_ID_ERROR;

            return $this->huoError($_code, OrderStatus::getMsg($_code), $_rdata);
        }
        $_code = OrderStatus::NO_ERROR;
        $_rdata = [
            'order_id'  => $order_id,
            'status'    => $_statues['status'],
            'cp_status' => $_statues['cp_status']
        ];

        return $this->huoSuccess($_code, OrderStatus::getMsg($_code), $_rdata);
    }

    /**
     * @param string $app_id  应用ID
     * @param bool   $is_sand 是否沙盒环境
     *
     * @return array
     */
    public function getBaseParam($app_id, $is_sand = false) {
        $_mpay_data = (new GameMini())->getMpayConf($app_id, $is_sand);
        $_rdata['appid'] = $_mpay_data['appid'];        /* 小程序ID */
        $_rdata['offer_id'] = $_mpay_data['offer_id'];  /* 米大师支付应用ID */
        $_rdata['ts'] = time();
        $_rdata['zone_id'] = '1';
        $_rdata['pf'] = 'android';
        $_rdata['app_secret'] = $_mpay_data['app_secret'];  /* 小程序AppSecret */
        $_rdata['app_key'] = $_mpay_data['app_key'];        /* 米大师AppKey */

        return $_rdata;
    }

    /**
     * @param int $mem_id
     * @param int $app_id
     *
     * @return string
     */
    public function getOpenId($mem_id, $app_id = 0) {
        $_open_id = (new HuoSession($mem_id, $app_id))->getOpenId();
        if (!empty($_open_id)) {
            return $_open_id;
        }

        return '';
    }

    /**
     * @param int $mem_id
     * @param int $app_id
     *
     * @return string
     */
    public function getSessionKey($mem_id, $app_id) {
        $_session_key = (new HuoSession($mem_id, $app_id))->getAccessToken();
        if (!empty($_session_key)) {
            return $_session_key;
        }

        return '';
    }

    /**
     * 开通了虚拟支付的小游戏,可以通过本接口查看某个用户的游戏币余额
     * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasGetBalance.html
     *
     * @param int    $mem_id   玩家ID
     * @param string $order_id 订单ID
     *
     * @return int|mixed
     */
    public function midasGetBalance($mem_id, $order_id = '') {
        $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id);
        $_is_sand = true;
        if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) {
            $_is_sand = false;
        }
        $_app_id = $_order_data['app_id'];
        $_uri = '/cgi-bin/midas/getbalance';
        if ($_is_sand) {
            $_uri = '/cgi-bin/midas/sandbox/getbalance';
        }
        $_base_params = $this->getBaseParam($_app_id, $_is_sand);
        $_open_id = $this->getOpenId($mem_id, $_app_id);
        $_session_key = $this->getSessionKey($mem_id, $_app_id);
        $_params = [
            'openid'   => $_open_id,
            'appid'    => $_base_params['appid'],
            'offer_id' => $_base_params['offer_id'],
            'ts'       => $_base_params['ts'],
            'zone_id'  => $_base_params['zone_id'],
            'pf'       => $_base_params['pf'],
            //'user_ip'       => $_order_data['payext']['ip'],/* 用户外网 IP */
        ];
        $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */
        $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */
        $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key);
        if (OrderStatus::NO_ERROR == $_rs['code']) {
            $_mgm_log_data['mem_id'] = $mem_id;
            $_mgm_log_data['app_id'] = $_order_data['app_id'];
            $_mgm_log_data['order_id'] = $_order_data['order_id'];
            $_mgm_log_data['m_balance'] = $_rs['data']['balance'];
            $_mgm_log_data['m_gen_balance'] = $_rs['data']['gen_balance'];
            $_mgm_log_data['m_save_amt'] = $_rs['data']['save_amt'];
            $_mgm_log_data['m_save_sum'] = $_rs['data']['save_sum'];
            $_mgm_log_data['m_cost_sum'] = $_rs['data']['cost_sum'];
            $_mgm_log_data['m_present_sum'] = $_rs['data']['present_sum'];
            $_mgm_log_data['server_id'] = $_base_params['zone_id'];
            $_mgm_log_data['type'] = self::MGM_QUERY;
            (new MgmLogModel())->insertLog($_mgm_log_data);
        }

        return $_rs;
    }

    /**
     * 开通了虚拟支付的小游戏,若扣除游戏币的订单号在有效时间内,可以通过本接口取消该笔扣除游戏币的订单
     * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasCancelPay.html
     *
     *
     * @param int    $mem_id   玩家ID
     * @param string $order_id 订单ID
     *
     * @return array|mixed
     */
    function midasCancelPay($mem_id, $order_id) {
        $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id);
        $_is_sand = true;
        if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) {
            $_is_sand = false;
        }
        $_app_id = $_order_data['app_id'];
        $_uri = '/cgi-bin/midas/cancelpay';
        if ($_is_sand) {
            $_uri = '/cgi-bin/midas/sandbox/cancelpay';
        }
        $_base_params = $this->getBaseParam($_app_id, $_is_sand);
        $_open_id = $this->getOpenId($mem_id);
        $_session_key = $this->getSessionKey($mem_id);
        $_params = [
            'openid'   => $_open_id,
            'appid'    => $_base_params['appid'],
            'offer_id' => $_base_params['offer_id'],
            'ts'       => $_base_params['ts'],
            'zone_id'  => $_base_params['zone_id'],
            'pf'       => $_base_params['pf'],
            //'user_ip'       => $_order_data['payext']['ip'],/* 用户外网 IP */
            'bill_no'  => $_order_data['order_id'],
            // 'pay_item'       => $_order_data['payext']['product_name'], /* 道具名称 */
        ];
        $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */
        $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */
        $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key);
        if (OrderStatus::NO_ERROR == $_rs['code']) {
            $_mgm_log_data['mem_id'] = $mem_id;
            $_mgm_log_data['app_id'] = $_order_data['app_id'];
            $_mgm_log_data['order_id'] = $_order_data['order_id'];
            $_mgm_log_data['type'] = self::MGM_CANCEL;
            (new MgmLogModel())->insertLog($_mgm_log_data);
        }

        return $_rs;
    }

    /**
     * 米大师付款
     * 开通了虚拟支付的小游戏,可以通过本接口扣除某个用户的游戏币。
     * 由于可能存在接口调用超时或返回系统失败,但是游戏币实际已经扣除的情况,所以当该接口返回系统失败时,可以用相同的bill_no再次调用本接口,直到返回非系统失败为止,不会重复扣款,也可以调用取消支付接口取消本次扣款。
     * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasPay.html
     *
     *
     * @param int    $mem_id   玩家ID
     * @param string $order_id 订单ID
     *
     * @return array|mixed
     */
    function midasPay($mem_id, $order_id) {
        $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id);
        $_is_sand = true;
        if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) {
            $_is_sand = false;
        }
        $_app_id = $_order_data['app_id'];
        $_uri = '/cgi-bin/midas/pay';
        if ($_is_sand) {
            $_uri = '/cgi-bin/midas/sandbox/pay';
        }
        $_base_params = $this->getBaseParam($_app_id, $_is_sand);
        $_open_id = $this->getOpenId($mem_id, $_app_id);
        $_session_key = $this->getSessionKey($mem_id, $_app_id);
        $_params = [
            'openid'   => $_open_id,
            'appid'    => $_base_params['appid'],
            'offer_id' => $_base_params['offer_id'],
            'ts'       => $_base_params['ts'],
            'zone_id'  => $_base_params['zone_id'],
            'pf'       => $_base_params['pf'],
            //            'user_ip'       => $_order_data['payext']['ip'],
            //            'pay_item'       => $_order_data['payext']['product_name'],
            //            'app_remark'       => $_order_data['payext']['remark'],
            'amt'      => $_order_data['product_cnt'], /* 扣除游戏币数量,不能为 0 */
            'bill_no'  => $_order_data['order_id'],
        ];
        $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */
        $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */
        $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key);
        if (OrderStatus::NO_ERROR == $_rs['code']) {
            $_mgm_log_data['mem_id'] = $mem_id;
            $_mgm_log_data['app_id'] = $_order_data['app_id'];
            $_mgm_log_data['order_id'] = $_rs['data']['bill_no'];
            $_mgm_log_data['m_balance'] = $_rs['data']['balance'];
            $_mgm_log_data['m_used_gen_balance'] = isset($_rs['data']['used_gen_amt'])
                ? $_rs['data']['used_gen_amt'] : 0;
            $_mgm_log_data['type'] = self::MGM_PAY;
            (new MgmLogModel())->insertLog($_mgm_log_data);
        }

        return $_rs;
    }

    /**
     * 米大师赠送
     * 开通了虚拟支付的小游戏,可以通过该接口赠送游戏币给某个用户。
     * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasPresent.html
     *
     *
     * @param int    $mem_id         玩家ID
     * @param string $order_id       订单ID
     * @param int    $present_counts 赠送游戏币的个数,不能为0
     *
     *
     * 0    请求成功
     * -1    系统繁忙,此时请开发者稍候再试
     * 90009    mp_sig签名错误
     * 90010    用户未登录或登录态已过期
     * 90011    sig签名错误
     * 90012    订单已存在
     * 90017    没有调用接口的权限
     * 90018    参数错误
     *
     * @return array|mixed
     */
    function midasPresent($mem_id, $order_id, $present_counts) {
        $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id);
        $_is_sand = true;
        if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) {
            $_is_sand = false;
        }
        $_app_id = $_order_data['app_id'];
        $_uri = '/cgi-bin/midas/present';
        if ($_is_sand) {
            $_uri = '/cgi-bin/midas/sandbox/present';
        }
        $_base_params = $this->getBaseParam($_app_id, $_is_sand);
        $_open_id = $this->getOpenId($mem_id);
        $_session_key = $this->getSessionKey($mem_id);
        $_params = [
            'openid'         => $_open_id,
            'appid'          => $_base_params['appid'],
            'offer_id'       => $_base_params['offer_id'],
            'ts'             => $_base_params['ts'],
            'zone_id'        => $_base_params['zone_id'],
            'pf'             => $_base_params['pf'],
            //            'user_ip'       => $_order_data['payext']['ip'],
            'bill_no'        => $_order_data['order_id'],
            'present_counts' => $present_counts, /* 赠送游戏币的个数,不能为0 */
        ];
        $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */
        $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */
        $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key);
        if (OrderStatus::NO_ERROR == $_rs['code']) {
            $_mgm_log_data['mem_id'] = $mem_id;
            $_mgm_log_data['app_id'] = $_order_data['app_id'];
            $_mgm_log_data['order_id'] = $_rs['data']['bill_no'];
            $_mgm_log_data['m_balance'] = $_rs['data']['balance'];
            $_mgm_log_data['type'] = self::MGM_PRESENT;
            (new MgmLogModel())->insertLog($_mgm_log_data);
        }

        return $_rs;
    }
}