<?php

namespace app\api\controller;

use addons\epay\library\Service;
use app\common\controller\Api;
use app\utils\CurlUtil;
use app\utils\Easywechat\MiniAppService;
use app\utils\LogUtil;
use app\utils\PayUtil;
use think\Cache;
use think\Db;
use think\Exception;
use think\Request;

/**
 * 通行证
 */
class HuiPay extends Api
{
    // 日志模块名称
    const LOG_MODULE = 'HuiPay';
    protected $noNeedLogin = ['vip_recharge', 'gold_recharge', 'pay', 'pay_notify'];
    protected $noNeedRight = '*';
    // h5 跳转小程序
    const H5 = 'https://mp-pay-0gk77hzo6366ff37-1320524135.tcloudbaseapp.com';

    public function _initialize()
    {
        parent::_initialize();
    }

    public function __construct(Request $request = null)
    {
        parent::__construct($request);
        //日志统一写入
        register_shutdown_function([new LogUtil, 'close']);
        LogUtil::getInstance('Api/'); //设置日志存入通道
    }


    /**
     * 会员充值 (跳转小程序充值)
     * @return void
     */
    public function vip_recharge()
    {
        Db::startTrans();
        try {
            $rc_id = input('rc_id', 0);
            $pay_type = input('pay_type', 'wechat');
            $uid = $this->auth->id;

            if ($pay_type != 'wechat') {
                throw new Exception('支付类型有误');
            }

            if (!$rc_id) {
                throw new Exception('请选择会员套餐');
            }

            //赋值money
            $recharge_config = Db::name('payvip_config')->where('id', $rc_id)->find();
            $money = $recharge_config['money'];

            if ($money <= 0) {
                throw new Exception('支付金额必须大于0');
            }
            if ($money > 10000) {
                throw new Exception('支付金额太大');
            }

            //会员等级冲突
            //当前是会员,但是却要向下级续费,直接提示报错
            //修改等级,向上立刻改,向下不允许
            $wallet_info = model('wallet')->getWallet($this->auth->id);
            if ($wallet_info['vip_endtime'] > time() && $recharge_config['vip_level'] < $wallet_info['vip_level']) {
                throw new Exception('当前会员没有过期,不能续费');
            }

            //创建订单
            $data = [];
            $data['status'] = 0;
            $pay_no = createUniqueNo('V', $uid);
            $data['pay_no'] = $pay_no;
            $data['money'] = $money;
            $data['payment_class'] = $pay_type;
            $data['user_id'] = $uid;
            $data['ext_info'] = json_encode(['subject' => '充值vip支付']);
            $data['memo'] = '充值会员支付';
            $data['createtime'] = time();
            //$data['payment'] = 'miniapp';
            $data['payment'] = 'app';
            $pay_order = Db::name('pay_order')->insertGetId($data);

            //创建回调
            $even_data = [];
            $even_data['event'] = 'success';
            $even_data['class'] = 'app\common\model\Recharge';
            $even_data['method'] = 'vippaysucc';
            $even_data['args'] = json_encode(['user_id' => $uid, 'days' => $recharge_config['days'], 'vip_level' => $recharge_config['vip_level'], 'gold_num' => $recharge_config['gold_num'], 'money' => $money]);
            $even_data['pay_no'] = $pay_no;
            $pay_event = Db::name('pay_event')->insertGetId($even_data);

            if (!$pay_order || !$pay_event) {
                throw new Exception('下单失败');
            }

            // h5跳转小程序支付链接
            $url = self::H5 . "?order_no={$pay_no}&money=$money";
            Db::commit();
            $this->success('success', [
                'url' => $url
            ]);
        } catch (Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    }

    /**
     * 金币充值
     * @return void
     */
    public function gold_recharge()
    {
        Db::startTrans();
        try {
            $rc_id = input_post('rc_id', 0);
            $pay_type = 'wechat';
            $freemoney = input_post('freemoney', 0, 'intval');
            $uid = $this->auth->id;

            if (!$rc_id && !$freemoney) {
                throw new Exception('请选择或填写充值金额');
            }
            if (!in_array($pay_type, ['wechat', 'alipay'])) {
                throw new Exception('错误的支付类型');
            }
            //赋值money
            if ($rc_id) {
                $recharge_config = Db::name('paygold_config')->where('id', $rc_id)->find();
                $money = $recharge_config ? $recharge_config['money'] : 0;
                $gold = $recharge_config ? $recharge_config['gold'] : 0;
                $first_gold = $recharge_config ? $recharge_config['first_gold'] : 0;
                $first_vipdays = $recharge_config ? $recharge_config['first_vipdays'] : 0;
                $vip_gold = $recharge_config ? $recharge_config['vip_gold'] : 0;
            }

            //自由输入覆盖
            if (!empty($freemoney)) {
                $rc_id = 0;
                $money = floatval($freemoney);
                $bili = config('site.money_to_gold') ?: 10;
                $gold = bcmul($money, $bili, 0);
                $first_gold = 0;
                $first_vipdays = 0;
                $vip_gold = 0;
            }
            if ($money <= 0) {
                throw new Exception('支付金额必须大于0');
            }
            if ($money > 10000) {
                throw new Exception('支付金额太大');
            }
            //查询是不是会员,若不是则不赠送金币
            $vip_endtime = Db::name('user_wallet')->where('user_id', $this->auth->id)->value('vip_endtime');
            if ($vip_endtime < time()) {
                $vip_gold = 0;
            }

            //创建订单
            $data = [];
            $data['status'] = 0;
            $pay_no = createUniqueNo('P', $uid);
            $data['pay_no'] = $pay_no;
            $data['money'] = $money;
            $data['payment_class'] = $pay_type;
            $data['user_id'] = $uid;
            $data['ext_info'] = json_encode(['subject' => '充值金币支付']);
            $data['memo'] = '充值金币支付';
            $data['createtime'] = time();
            $data['payment'] = 'app';
            $pay_order = Db::name('pay_order')->insertGetId($data);

            //创建回调
            $even_data = [];
            $even_data['event'] = 'success';
            $even_data['class'] = 'app\common\model\Recharge';
            $even_data['method'] = 'goldpaysucc';
            $even_data['args'] = json_encode(['user_id' => $uid, 'gold' => $gold, 'money' => $money, 'pg_id' => $rc_id, 'first_gold' => $first_gold, 'first_vipdays' => $first_vipdays, 'intro_uid' => $this->auth->intro_uid, 'vip_gold' => $vip_gold]);
            $even_data['pay_no'] = $pay_no;
            $pay_event = Db::name('pay_event')->insertGetId($even_data);


            if (!$pay_order || !$pay_event) {
                throw new Exception('下单失败');
            }

            // h5跳转小程序支付链接
            $url = self::H5 . "?order_no={$pay_no}&money=$money";
            Db::commit();
            $this->success('success', [
                'url' => $url
            ]);
        } catch (Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    }

    /**
     * 汇付 支付
     */
    public function pay()
    {
        $params = \request()->post();
        $order_no = $params['order_no'] ?? '';
        if ($params['openid'] != 9696) {
            $wxInfo = Cache::get($params['openid'] ?? '');
            $openid = $wxInfo['openid'] ?? '';
        } else {
            $openid = 'ol8qS68vKSgWJ3Unrgfyi3rkakcQ';
        }

        if (empty($order_no) || empty($openid)) {
            $this->error('支付超时,请重新下单支付');
        }

        // 获取下单信息
        $order = Db::name('pay_order')->where('pay_no', $order_no)->find();
        if (!$order) {
            $this->error('订单不存在,请重新下单支付');
        }

        $money = $order['money'];
        $money = '0.01';// 测试支付

//        $order_no = "D0" . time();

        $pay = new PayUtil();
        $notify_url = CurlUtil::getHttp('/api/hui_pay/pay_notify', false);
        if (!$pay->jsPay($openid, $order_no, $money, $order['memo'] ?? '商品下单支付', $notify_url)) {
            $this->error($pay->getMessage());
        }

        $res = $pay->getData();
        if (empty($res['data']['pay_info']) || !$pay_info = json_decode($res['data']['pay_info'], true)) {
            $this->error('支付信息有误');
            // exit;
            // 这里 不加 exit 编辑器可能会提示  $pay_info 有可能不存在的变量 是因为 fastadmin 自带 error 写法不规范导致的
        }

        $this->success('success', [
            'pay_info' => $pay_info,// 这里编辑器可能会提示  有可能不存在的变量 是因为 fastadmin 自带 error 写法不规范导致的
            'order_no' => $order_no
        ]);
    }

    /**
     * 支付回调
     *
     * @param Request $request
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function pay_notify(Request $request)
    {
        $params = $request->param();

        // 消息主体信息
        $resp_data_json = htmlspecialchars_decode($params['resp_data'] ?? '');
        $resp_data = json_decode(stripslashes($resp_data_json), true);
        unset($params['resp_data']);

        LogUtil::info('支付回调参数', self::LOG_MODULE, __FUNCTION__, [
            'params' => $params,
//            'resp_data2' => $resp_data_json,
            'resp_data' => $resp_data,
        ]);

        // 校验回调信息
        if (empty($params['resp_code']) || $params['resp_code'] != '00000000' || empty($resp_data['req_seq_id'])) {
            LogUtil::info('回调信息有误', self::LOG_MODULE, __FUNCTION__, "resp_code error");
            return self::response201('支付信息有误');
        }

        // 校验签名
        $huiPay = new PayUtil();
        if (!$huiPay->checkSign($params['sign'],$resp_data_json)){
            LogUtil::info('签名校验失败', self::LOG_MODULE, __FUNCTION__);
            return self::response201('签名校验失败');
        }

        // 开始处理业务逻辑
        $pay_no = $resp_data['req_seq_id'];
        LogUtil::info('订单号', self::LOG_MODULE, __FUNCTION__, $pay_no);
        //查询订单信息
        $order_info = Db::name('pay_order')->where('pay_no', $pay_no)->find();
        if (!$order_info) {
            LogUtil::info('订单信息不存在', self::LOG_MODULE, __FUNCTION__);
            return self::response201('订单信息不存在');
        }
        if ($order_info['status'] == 1 || $order_info['status'] == 2) {
            LogUtil::info('充值入账更新余额失败_status已更新过', self::LOG_MODULE, __FUNCTION__, [
                'status' => $order_info['status']
            ]);
            return self::response201('充值入账失败');
        }

        $extendType = '';
        //区分vip 还是 冲金币
        $is_g = stripos($pay_no, 'P');
        if ($is_g !== false) {
            $extendType = 'gold';
        } else {
            $is_v = stripos($pay_no, 'V');
            if ($is_v !== false) {
                $extendType = 'vip';
            }
        }

        //status已更新过
        $result = Db::name('pay_order')->where('pay_no', $pay_no)->setField(['status' => 2]);

        if (!$result) {
            LogUtil::info('充值入账更新余额失败_status更新状态2不成功', self::LOG_MODULE, __FUNCTION__, [
                'status' => $order_info['status']
            ]);
            return self::response201('充值入账失败');
        }

        //你可以在此编写订单逻辑
        $payEvent = Db::name('pay_event')->where('pay_no', $pay_no)->find();
        $args = json_decode($payEvent['args'] ?? '', true);
        $rechargeM = new \app\common\model\Recharge();
        if ($extendType == 'gold') {
            $payRes = $rechargeM->goldpaysucc($pay_no, $args);
            $payTypeStr = '充值';
        } elseif ($extendType == 'vip') {
            $payRes = $rechargeM->vippaysucc($pay_no, $args);
            $payTypeStr = 'vip';
        } else {
            $payRes = false;
            $payTypeStr = '未知支付类型';
        }
        if (!$payRes) {
            LogUtil::info('更新失败', self::LOG_MODULE, __FUNCTION__, $payTypeStr);
            return self::response201('更新失败');
        }

        LogUtil::info('订单处理成功', self::LOG_MODULE, __FUNCTION__, $payTypeStr);
        return self::response200('success');
    }

    /**
     * 成功返回
     * @param string $message
     * @param $result
     * @return string
     */
    private static function response200(string $message = 'success', $result = null)
    {
        return json_encode([
            'code' => 200,
            'message' => $message,
            'result' => $result,
        ], JSON_UNESCAPED_UNICODE);
    }

    /**
     * 失败返回201
     * @param string $message
     * @param $result
     * @return string json
     */
    private static function response201(string $message = 'error', $result = null)
    {
        return json_encode([
            'code' => 201,
            'message' => $message,
            'result' => $result
        ], JSON_UNESCAPED_UNICODE);
    }
}