<?php

namespace App\Services;
use App\Http\Response\CatchError;
use App\Models\ESTP\User as EstpUser;
use App\Models\User;
use App\Models\Wechat;
use EasyWeChat\Kernel\Support\Str;
use EasyWeChat\MiniApp\Application;
use EasyWeChat\Work\Application as WorkApplication;
use EasyWeChat\OfficialAccount\Application as OfficialApplication;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Facades\UploadService;
use Symfony\Component\Cache\Psr16Cache;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;

class WechatService
{
    use CatchError;
    protected $app, $official_app, $official_access_token, $mp_access_token;

    public function __construct()
    {
        //小程序
        $config = config('wechat.mini_program');
        $app = new Application($config);
        $this->app = $app;
        //公众号
        $config = config('wechat.official_account.default');
        $official_app = new OfficialApplication($config);

        // $app->setCache(new Psr16Cache(app('cache.psr6')));


        //    $access_token_key = "mp_access_token";
        //    Log::info("当前access_token: {$app->getAccessToken()->getToken()}");
        //    if (config('app.env') == 'production') {
        //        if (Cache::has($access_token_key)) {
        //            $this->mp_access_token = Cache::get($access_token_key);
        //        }else {
        //            $app->getAccessToken()->refresh();
        //            $this->mp_access_token = $app->getAccessToken()->getToken();
        //            Cache::put($access_token_key, $this->mp_access_token, now()->addMinutes(90));
        //        }
        //    }
        //    Log::info("缓存access_token: {$this->mp_access_token}");

        //        $official_app->setCache(new Psr16Cache(app('cache.psr6')));
//        $app->setCache(new Psr16Cache(app('cache.psr6')));


        //        $access_token_key = "official_access_token";
//        Log::info("当前access_token: {$official_app->getAccessToken()->getToken()}");
//        if (config('app.env') == 'production') {
//            if (Cache::has($access_token_key)) {
//                $this->official_access_token = Cache::get($access_token_key);
//            }else {
//                $official_app->getAccessToken()->refresh();
//                $this->official_access_token = $official_app->getAccessToken()->getToken();
//                Cache::put($access_token_key, $this->official_access_token, now()->addMinutes(90));
//            }
//        }
//        Log::info("缓存access_token: {$this->official_access_token}");
        $this->official_app = $official_app;

    }

    public function instance()
    {
        //商户号
        $merchantId = config('wechat.payment.mch_id');
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = config('wechat.payment.serial');

        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://' . config('wechat.payment.certificate');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
        // 构造一个 APIv3 客户端实例
        $instance = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        return $instance;

    }

    public function app()
    {
        return $this->app;
    }

    /**
     * 公众号
     * @return \EasyWeChat\OfficialAccount\Application
     */
    public function officialApp()
    {
        return $this->official_app;
    }
    /**
     * 企业微信
     * @return WorkApplication
     */
    public function workApp($type)
    {
        $work_config = config('wechat.' . $type);
        $work_app = new WorkApplication($work_config);
        return $work_app;
    }


    /**
     * 小程序code 换取session 信息
     * @param $code
     * @param string $grant_type
     * @return array
     * @throws \Exception
     */
    public function codeToSession($code, $grant_type = 'authorization_code')
    {
        try {
            $utils = $this->app->getUtils();
            $response = $utils->codeToSession($code);
            return $response;
        } catch (\Throwable $e) {
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 小程序code换取手机号信息
     * @param $code
     * @return array|string[]
     * @throws \Exception
     */
    public function phoneNuber($code)
    {
        try {
            if (env('APP_ENV') == 'local')
                return ['mobile' => '15872844805'];
            $data = ['code' => (string) $code];
            $res = $this->app->getClient()->postJson('wxa/business/getuserphonenumber', $data);
            if ($res->isFailed())
                throw new \Exception($res->getContent());
            $r = json_decode($res->toJson());
            return ['mobile' => $r->phone_info->phoneNumber];
        } catch (\Throwable $e) {
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 小程序订阅消息列表
     * @return mixed|null
     * @throws \Exception
     */
    public function templates()
    {
        try {
            $res = $this->app->getClient()->get('wxaapi/newtmpl/gettemplate');
            if ($res->isFailed())
                throw new \Exception($res->getContent());
            return $res['data'] ?? null;
        } catch (\Throwable $e) {
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 小程序发送订阅消息
     * @param $openid
     * @param $template_id
     * @param $page
     * @param array $data
     * @return bool|int|mixed
     */
    public function subSend($openid, $template_id, $page, $data = [])
    {
        try {
            if (empty($openid))
                return false;
            $all_data = [
                'template_id' => $template_id,
                'touser' => $openid,
                'page' => $page,
                'data' => $data,
                'miniprogram_state' => (env('APP_ENV') == 'production') ? 'formal' : 'developer',
                'lang' => 'zh_CN',
            ];
            $client = $this->app->getClient();
            $response = $client->postJson('cgi-bin/message/subscribe/send', $all_data);
            $all_data['type'] = 'mp';
            if ($response['errcode']) {
                $all_data['err_msg'] = $response['errmsg'];
                $all_data['status'] = 0;
            } else {
                $all_data['err_msg'] = '';
                $all_data['status'] = 1;
            }
            //            $this->addTemplateMsgLog($all_data);
            return $response['errcode'] ?? 1;
        } catch (\Throwable $e) {
            $this->getError($e);
            return true;
        }
    }

    //    public function addTemplateMsgLog($data)
//    {
//        $where = $data['type'] == 'mp'?['openid'=>$data['touser']]:['official_openid'=>$data['touser']];
//        $user_id = Wechat::where($where)->value('user_id');
//        $log = new TemplateMsgLog;
//        $log->user_id = $user_id;
//        $log->openid = $data['touser'];
//        $log->type = $data['type'];
//        $log->template_id = $data['template_id'];
//        $log->status = $data['status'];
//        $log->err_msg = $data['err_msg']??'';
//        $log->data = json_encode($data);
//        $log->save();
//        return true;
//    }

    /**
     * 获取小程序二维码
     * @param $scene
     * @param $page
     * @param string $env_version 正式版为 "release"，体验版为 "trial"，开发版为 "develop"。默认是正式版。
     * @param int $width
     * @param bool $is_hyaline
     * @return string
     * @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function getMPQrcode($scene, $page, $env_version = 'release', $width = 430, $is_hyaline = true)
    {
        $app = $this->app;
        $response = $app->getClient()->postJson('/wxa/getwxacodeunlimit', [
            'scene' => $scene,
            'page' => $page,
            'width' => $width,
            'is_hyaline' => $is_hyaline,
            'env_version' => $env_version,
            'check_path' => false
        ]);
        $file_name = uniqid() . time() . 'qrcode.png';
        $path = storage_path('qrcode/' . $file_name);
        $response->saveAs($path);
        $pic = '';
        if (file_exists($path)) {
            $pic = UploadService::uploadFile($path);
            @unlink($path);
        }
        return $pic;
    }

    /**
     * 小程序支付
     * @param $trade_no
     * @param $openid
     * @param $total
     * @param $desc
     * @param $callback
     * @return array|false
     */
    public function mpPay($trade_no, $openid, $total, $desc, $callback, $appId = '', $sub_mchid = '')
    {
        if (config('wechat.payment.debug')) {
            return false;
        }
        $sub_appid = config('wechat.payment.sub_app_id');
        if ($appId) {
            $sub_appid = $appId;
        }
        $resp = $this->instance()
            ->chain('v3/pay/partner/transactions/jsapi')
            ->post([
                'json' => [
                    'sp_mchid' => config('wechat.payment.mch_id'),
                    'sp_appid' => config('wechat.payment.sp_appid'),
                    'sub_appid' => $sub_appid,
                    'sub_mchid' => $sub_mchid ?: config('wechat.payment.sub_merchant_id'),
                    'out_trade_no' => $trade_no,
                    'description' => $desc,
                    'notify_url' => $callback,
                    'amount' => [
                        'total' => (int) number_format($total * 100, 0, '', ''),
                        'currency' => 'CNY'
                    ],
                    'payer' => [
                        'sub_openid' => $openid,
                    ]
                ]
            ]);
        $res = json_decode($resp->getBody());
        $prepay_id = $res->prepay_id;
        $config = $this->paySign($prepay_id, $sub_appid);
        $config['prepay_id'] = $prepay_id;
        return $config;
    }

    /**
     * 获取jssdk配置
     * @param $url
     * @return mixed[]
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    //    public function getOfficialShareConfig($url){
//        $app = $this->officialApp();
//        $config = $app->getUtils()->buildJsSdkConfig($url, ['updateAppMessageShareData','updateTimelineShareData','onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems','showMenuItems'], ['wx-open-launch-weapp'], false);
//        return $config;
//    }

    public function buildJsSdkConfig($url)
    {
        //        $app = $this->officialApp();
//        $api = $app->getClient();
        $token_url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
        $params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
        try {
            $res = \App\Facades\HttpService::postData($token_url, $params);
            $access_token = $res['data'];
        } catch (\Exception $e) {
            $access_token = '';
        }
        //        $res = $api->get("cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
//        if ($res->isFailed()) {
//
//        }
//        $res = json_decode($res->toJson(),true);
        $ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $access_token . "&type=jsapi";
        $res = \App\Facades\HttpService::getData($ticket_url);
        Log::info("获取微信ticket  cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
        Log::info($res);
        $ticket = $res['ticket'];
        $nonce = Str::random();
        $timestamp = time();
        $signature = sha1("jsapi_ticket=$ticket&noncestr=$nonce&timestamp=$timestamp&url=$url");
        $jsApiList = ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems', 'showMenuItems'];
        $openTagList = ['wx-open-launch-weapp'];
        return [
            'appId' => config('wechat.official_account.default.app_id'),
            'beta' => false,
            'debug' => false,
            'jsApiList' => $jsApiList,
            'nonceStr' => $nonce,
            'openTagList' => $openTagList,
            'signature' => $signature,
            'timestamp' => $timestamp,
            'url' => $url,
        ];
    }

    /**
     * 退款
     * @param $trade_no
     * @param $refund_trade_no
     * @param $total_amount
     * @param $refund_amount
     * @param array $array
     * @return array
     */
    public function refund($trade_no, $refund_trade_no, $total_amount, $refund_amount, $callback, $sub_mchid = '')
    {
        if (config('wechat.payment.debug')) {
            return ["status" => true, 'msg' => ''];
        }
        if (!$sub_mchid) {
            $sub_mchid = config('wechat.payment.sub_merchant_id');
        }
        try {
            $resp = $this->instance()
                ->chain('v3/refund/domestic/refunds')
                ->post([
                    'json' => [
                        'sub_mchid' => $sub_mchid,
                        'out_trade_no' => $trade_no,
                        'out_refund_no' => $refund_trade_no,
                        'notify_url' => $callback,
                        'amount' => [
                            'total' => (int) number_format($total_amount * 100, 0, '', ''),
                            'refund' => (int) number_format($refund_amount * 100, 0, '', ''),
                            'currency' => 'CNY'
                        ],
                    ]
                ]);
            $res = json_decode($resp->getBody());
            Log::info($resp->getBody());
            if ($res->status == 'PROCESSING' || $res->status == "SUCCESS") {
                return ['status' => true, 'msg' => ''];
            }
            return ['status' => false, 'msg' => '打款失败'];
        } catch (\Exception $e) {
            $msg = $e->getMessage();
            Log::info($msg);
            return ['status' => false, 'msg' => $msg];
        }

    }

    /**
     * 退款订单查询
     * @param  string $refund_trade_no 退款订单号
     */
    public function orderRefunded($refund_trade_no, $sub_mch_id = null)
    {
        if (config('wechat.payment.debug')) {
            return ['status' => true, 'message' => ""];
        }
        try {
            if (!$sub_mch_id) {
                $sub_mch_id = config('wechat.payment.sub_merchant_id');
            }
            $resp = $this->instance()
                ->chain('v3/refund/domestic/refunds/' . $refund_trade_no)
                ->get([
                    'query' => [
                        'sub_mchid' => $sub_mch_id
                    ],
                    'out_refund_no' => $refund_trade_no,
                ]);
            $res = json_decode($resp->getBody());
            if ($res->status == 'SUCCESS') {
                return ['status' => true, 'message' => ""];
            }
            return ['status' => false, 'message' => "退款失败"];
        } catch (\Exception $e) {
            Log::debug($refund_trade_no . '订单查询退款异常:' . $e->getMessage());
            return ['status' => false, 'message' => $e->getMessage()];
        }
    }
    /**
     * 小程序-查询订单是否支付
     * @param $trade_no
     * @return bool
     */
    public function mpPaid($trade_no, $sub_mch_id = '')
    {
        if (config('wechat.payment.debug')) {
            return false;
        }
        if (empty($sub_mch_id)) {
            $sub_mch_id = config('wechat.payment.sub_merchant_id');
        }
        $resp = $this->instance()
            ->chain('v3/pay/partner/transactions/out-trade-no/' . $trade_no)
            ->get([
                // Query 参数
                'query' => [
                    'sp_mchid' => config('wechat.payment.mch_id'),
                    'sub_mchid' => $sub_mch_id,
                ],
                // 变量名 => 变量值
                'out_trade_no' => $trade_no,
            ]);
        Log::info($resp->getBody());
        $res = json_decode($resp->getBody());
        if (empty($res))
            return true;
        if ($res->trade_state == 'NOTPAY' || $res->trade_state == "CLOSED")
            return $res->trade_state_desc;
        return false;
    }

    /**
     * 小程序-支付签名
     * @param $prepay_id
     * @return array
     */
    public function paySign($prepay_id, $sub_appid)
    {
        $merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);
        $params = [
            //            'appId'     => config('wechat.mini_program.app_id'),
            'appId' => $sub_appid,
            'timeStamp' => (string) Formatter::timestamp(),
            'nonceStr' => Formatter::nonce(),
            'package' => 'prepay_id=' . $prepay_id,
        ];
        $params += [
            'paySign' => Rsa::sign(
                Formatter::joinedByLineFeed(...array_values($params)),
                $merchantPrivateKeyInstance
            ),
            'signType' => 'RSA'
        ];

        return $params;
    }

    public function sendSubscribeMessage($params)
    {
        if (config('app.env') == 'production') {

            $app = $this->app;
            //        $accessToken = $app->getAccessToken();
//        $accessToken->getToken();
            $response = $app->getClient()->postJson('cgi-bin/message/subscribe/send', $params);
            // if ($response['errcode'] && $response['errcode'] != "43101") {
            Log::info($params);
            //todo 发送失败
            //     throw new \Exception($response['errmsg']);
            // }
        }
    }

    /**
     * 公众号-后台服务
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \EasyWeChat\Kernel\Exceptions\BadRequestException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \ReflectionException
     * @throws \Throwable
     */
    public function server()
    {
        $app = $this->officialApp();
        $server = $app->getServer();
        $server->with(function ($message, \Closure $next) {
            Log::info("api server");
            // 你的自定义逻辑
//            Log::info($message);

            $openid = $message->FromUserName;
            //获取微信用户信息
            $info = $this->wechatUserByOfficialOpenid($openid);
            Log::info($openid . '用户信息', $info);
            if ($message->MsgType == 'event') {
                if ($message->Event == 'subscribe' || $message->Event == 'unsubscribe') {//关注
                    //同步健康信息
                    $this->syncSubscribe($info);
                }
            }
            //同步创业家项目关注信息
//            $this->syncEstpSubscribe($info);
            return $next($message);
        });

        return $server->serve();
    }

    /**
     * 同步公众号关注
     * @param $info
     */
    public function syncSubscribe($info)
    {
        $subscribe = $info['subscribe'];
        if ($subscribe) {
            //是否有本地小程序信息信息
            $wechat = Wechat::where(['unionid' => $info['unionid'], 'type' => 'mp'])->first();
            //            if (empty($wechat)) return ;
            DB::beginTransaction();
            //是否有本地公众号信息信息
            $official_wechat = Wechat::where('type', 'official')
                ->where('openid', $info['openid'])
                ->first();
            if (empty($official_wechat))
                return;
            //            if (!empty($wechat)){
//                $official_wechat->user_id = $wechat->user_id;
//            }
            $official_wechat->unionid = $info['unionid'];
            $official_wechat->save();
        } else {
            $official_wechat = Wechat::where(['openid' => $info['openid'], 'type' => 'official'])->first();
            if (empty($official_wechat))
                return;
        }
        //同步关注信息
        User::where('id', $official_wechat->user_id)->update(['is_subscribe' => $subscribe]);
        DB::commit();
    }

    /**
     * 同步创业家项目关注
     * @param $info
     */
    public function syncEstpSubscribe($info)
    {
        $subscribe = $info['subscribe'];
        if ($subscribe) {
            //关注
            $user = EstpUser::query()->where('unionid', $info['unionid'])->first();
            if ($user) {
                $user['is_subscribe'] = $subscribe;
                $user['openid'] = $info['openid'];
                $user->save();
            }

        } else {
            //取关
            $user = EstpUser::query()->where('openid', $info['openid'])->first();
            if ($user) {
                $user['is_subscribe'] = $subscribe;
                $user['open_recommend'] = $subscribe;
                $user->save();
            }
        }

        if ($user) {
            Log::info([
                'msg' => '已更新创业家' . ['取关', '关注'][$subscribe] . '信息',
                'data' => $user->toArray(),
            ]);
        }

    }

    /**
     * 公众号-通过openid获取用户信息
     * @param $openid
     * @return mixed
     * @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function wechatUserByOfficialOpenid($openid)
    {
        //        $app = $this->officialApp();
//        $api = $app->getClient();
        //处理token过期报错
//        $accessToken = $this->official_access_token;
//        $accessToken = $app->getAccessToken()->getToken();
        $url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
        $params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
        try {
            $res = \App\Facades\HttpService::postData($url, $params);
            $access_token = $res['data'];
        } catch (\Exception $e) {
            $access_token = '';
        }

        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$access_token&openid=$openid";
        $res = \App\Facades\HttpService::getData($url);
        return $res;
        //        $response = $api->get('/cgi-bin/user/info', [
//            "openid" => $openid,
//            "access_token" => $access_token,
//        ]);
//        if ($response->isFailed()) {
//            throw new \Exception("通过openid获取用户微信信息失败, ".$response->getContent());
//        }
//        $content = $response->toJson();
//        return json_decode($content,true);
    }

    /**
     * 公众号-发送模板消息
     * @param $param
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function sendTemplateNotice($param)
    {
        if (config('app.env') == 'production') {
            //            $app = $this->officialApp();
//            $api = $app->getClient();
//            $accessToken = $app->getAccessToken()->getToken();
//            $accessToken = $this->official_access_token;
            $url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
            $params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
            try {
                $res = \App\Facades\HttpService::postData($url, $params);
                $access_token = $res['data'];
            } catch (\Exception $e) {
                $access_token = '';
            }

            $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $access_token;
            $res = \App\Facades\HttpService::postData($url, $param);
            //            $response = $api->postJson('/cgi-bin/message/template/send?access_token=' . $access_token, $param);
//            if ($response->isFailed()) {
//                $errMsg = $response->toJson();
//                $errMsg = json_decode($errMsg,true);
//                if (isset($errMsg['errcode']) && $errMsg['errcode'] == 40001) {
//                    $app->getAccessToken()->refresh();
//                    $newResponse = $api->postJson('/cgi-bin/message/template/send', $param);
//                    Log::error("sendTemplateNotice1".$newResponse->getContent());
//                throw new \Exception("发送模板消息失败, ".$response->getContent());
//                }
//                Log::error("sendTemplateNotice" . $response->getContent());
//            }
        }
    }

    /**
     * 获取公众号二维码
     * @param $param
     * @return mixed
     * @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function getOfficialQrcode($param)
    {
        //        $app = $this->officialApp();
//        $api = $app->getClient();
//        $accessToken = $this->official_access_token;
        $url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
        $params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
        try {
            $res = \App\Facades\HttpService::postData($url, $params);
            $access_token = $res['data'];
        } catch (\Exception $e) {
            $access_token = '';
        }

        $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" . $access_token;
        $res = \App\Facades\HttpService::postData($url, $param);
        return $res;
        //        $response = $api->postJson('/cgi-bin/qrcode/create?access_token=' . $access_token, $param);
//        $content = $response->toJson();
//        return json_decode($content,true);
    }
    /**
     * 发送群消息
     * @param $touser
     * @param $msgtype
     * @param $content
     * @param string $toparty
     * @param string $totag
     * @param int $enable_duplicate_check
     * @param int $duplicate_check_interval
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function sendWorkMessage($touser, $msgtype, $content, $toparty = '', $totag = '', $enable_duplicate_check = 0, $duplicate_check_interval = 1800)
    {

        $api = $this->workApp('work_application')->getClient();

        $params = [
            "touser" => $touser,
            'toparty' => $toparty,
            'totag' => $totag,
            "msgtype" => $msgtype,
            "agentid" => 1000008,
            "safe" => 0,
            $msgtype => $content,
            "enable_duplicate_check" => $enable_duplicate_check,
            "duplicate_check_interval" => $duplicate_check_interval
        ];
        $response = $api->postJson('/cgi-bin/message/send', $params);
        if ($response->isFailed()) {
            // 出错了，处理异常
            throw new \Exception($response->getContent());
        }
    }

    /**
     * 发送应用消息
     * @param $chatid
     * @param $msgtype
     * @param $content
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function sendAppChat($chatid, $msgtype, $content)
    {
        $api = $this->workApp('work_application')->getClient();
        //        $access_token = $this->workApp()->getAccessToken()->getToken();
//        dd($access_token);
        $params = [
            'chatid' => $chatid,
            'msgtype' => $msgtype,
            'content' => $content,
            'safe' => 0
        ];
        $response = $api->postJson("/cgi-bin/appchat/send", $params);
        if ($response->isFailed()) {
            // 出错了，处理异常
            throw new \Exception($response->getContent());
        }
        //        dd($response->getContent());
    }

    /**
     * 微信公众号授权-获取code
     * @param $redirect_uri
     * @return string|void
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     */
    public function connectAuth($redirect_uri) //snsapi_userinfo
    {
        $app = $this->officialApp();
        $oauth = $app->getOauth();
        $wechat_user = session('wechat_user');
        $openid = $wechat_user['id'] ?? null;
        if (empty($openid)) {
            session(['intend_url' => $redirect_uri]);
            //            Log::info($redirect_uri);
            //生成完整的授权URL
            $redirectUrl = $oauth->redirect($redirect_uri);
            //            Log::info($redirectUrl);

            return $redirectUrl;
        }
    }

    /**
     * 微信公众号授权-获取维信息
     * @param $code
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Session\SessionManager|\Illuminate\Session\Store|mixed|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     */
    public function connectAuthByCode($code)
    {
        //        Log::info("wechat code: ". $code);
        try {
            $app = $this->officialApp();
            $oauth = $app->getOauth();

            $user = $oauth->userFromCode($code);

            session(['wechat_user' => $user->toArray()]);

            $targetUrl = session('intend_url') ?: '/';
            return $targetUrl;
        } catch (\Exception $e) {
            // 获取异常错误信息
            $errorMessage = $e->getMessage();
            // 进行错误处理，例如记录日志或返回给前端
            Log::error("connectAuthByCode error: " . $errorMessage);
        }

    }
    public function connectWorkAuthByCode($code, $config = 'work_application')
    {
        Log::info("wechat code: " . $code);
        $app = $this->workApp($config);

        Log::info("缓存测试 " . $code);
        $user = $app->getOAuth()->detailed()->userFromCode($code);

        //        $user = $oauth->userFromCode($code);
//        Log::info($user->toArray());
        //缓存用户信息
        Log::info("缓存用户信息");
        //        Log::info($user->toArray());
        session(['work_wechat_user' => $user->toArray()]);
        $targetUrl = session('intend_url') ?: '/';
        return $targetUrl;
    }

    public function connectWorkAuth($redirect_uri, $config = 'work_application') //snsapi_userinfo
    {
        Log::info("connectWorkAuth " . $redirect_uri);
        session(['intend_url' => $redirect_uri]);
        $app = $this->workApp($config);
        $redirect_uri = $app->getOAuth()->redirect($redirect_uri);

        return $redirect_uri;
    }

    /**
     * 获取企业微信jsSDK
     * @param $url
     * @param $type
     * @return array|mixed[]
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
     */
    public function workJsSdkConfig($url, $type)
    {
        $config = [];
        if ($type == 'work') {
            $utils = $this->workApp('work')->getUtils();
            $config = $utils->buildJsSdkConfig(
                $url,
                [],
                [],
                false,
            );
            //            $config['jsapi_ticket'] = $this->workApp('work')->getTicket()->getTicket();
        } elseif ($type == 'app') {
            $utils = $this->workApp('work_application')->getUtils();
            $config = $utils->buildJsSdkAgentConfig(
                config('wechat.work_application.agent_id'),
                $url,
                [],
                [],
                false,
            );
            //            $config['jsapi_ticket'] = $this->workApp('work_application')->getTicket()->getAgentTicket(1000003);
        }
        return $config;
    }

    public function groupChats($cursor = '', $limit = 15, $status_filter = 0, $userid_list = [])
    {
        $api = $this->workApp('work')->getClient();
        $response = $api->postJson('/cgi-bin/externalcontact/groupchat/list', [
            'status_filter' => $status_filter,
            'owner_filter' => [
                'userid_list' => $userid_list
            ],
            'cursor' => $cursor,
            'limit' => $limit
        ]);
        if ($response->isFailed()) {
            // 出错了，处理异常
            throw new \Exception($response->getContent());
        }
        return json_decode($response->toJson());
    }

    public function groupChat($chat_id, $need_name = 0)
    {
        try {
            $api = $this->workApp('work')->getClient();
            $response = $api->postJson('/cgi-bin/externalcontact/groupchat/get', [
                'chat_id' => $chat_id,
                'need_name' => $need_name
            ]);
            //        if ($response->isFailed()) {
//            // 出错了，处理异常
//            throw new \Exception($response->getContent());
//        }
            $res = json_decode($response->toJson());
            return $res;

        } catch (\Exception $e) {
            $this->getError($e);
            return false;
        }

    }

    public function workUserInfo($user_id)
    {
        $api = $this->workApp('work')->getClient();
        $response = $api->get('/cgi-bin/user/get', ['userid' => $user_id]);
        if ($response->isFailed()) {
            // 出错了，处理异常
            throw new \Exception($response->getContent());
        }
        //        Log::info($response->toJson());

        return json_decode($response->toJson());
    }

    public function test()
    {
        $access = $this->official_app->getAccessToken()->getToken();
        dd($access);
    }


    /**
     * 获取小程序 url link
     */
    public function urlLink($path, $query)
    {
        $data = [
            "path" => $path,
            "query" => $query,
        ];

        $res = $this->app->getClient()->post('wxa/generate_urllink', [
            'json' => $data
        ]);
        if ($res->isFailed())
            throw new \Exception($res->getContent());
        $r = json_decode($res->toJson());
        return $r->url_link;
    }

    public function getUrlLink($url_link)
    {
        $data = [
            'url_link' => $url_link,
        ];
        $res = $this->app->getClient()->postJson('wxa/query_urllink', $data);
        if ($res->isFailed())
            throw new \Exception($res->getContent());
        $r = json_decode($res->toJson());
        return $r->url_link_info;
    }

    public function getUserStep($code, $iv, $encryptedData)
    {
        try {
            $app = $this->app;
            $utils = $app->getUtils();
            $response = $utils->codeToSession($code);
            // 获取解密后的用户数据
            $userInfo = $utils->decryptSession($response['session_key'], $iv, $encryptedData);

            // 用户的微信步数
            $stepInfoList = $userInfo['stepInfoList'];
            $stepCount = end($stepInfoList); // 获取最近一天的步数
            $stepCount['stepInfoList'] = $stepInfoList;
            return $stepCount;
        } catch (\Throwable $e) {
            throw new \Exception($e->getMessage());
        }
    }

    public function getMpUrlLink($url, $query = null)
    {
        // $access_token = $this->app->getAccessToken()->getToken();
        $token_url = config('app.url') . '/go/api/mp/v1/common/accesstoken_mp/get';
        $params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
        try {
            $res = \App\Facades\HttpService::postData($token_url, $params);
            $access_token = $res['data'];
        } catch (\Exception $e) {
            $access_token = '';
        }
        $res = $this->app->getClient()->post('wxa/generatescheme?access_token=' . $access_token, [
            'json' => [
                'jump_wxa' => [
                    'path' => $url,
                    'query' => $query
                ],
                "is_expire" => true,
                "expire_time" => time() + 30 * 24 * 60 * 60
            ]
        ]);
        if ($res->isFailed())
            throw new \Exception($res->getContent());
        $r = json_decode($res->toJson());
        return $r->openlink;
    }
}
