<?php

namespace App\Common\Services;
use App\Common\Library\AES;
use App\Exceptions\ApiException;
use App\Services\CommonBaseService;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class WechatService extends CommonBaseService
{
    protected $cache = true;

    protected $cacheBucket = 'wechat:';

    protected $client = null;

    protected $appId = null;
    protected $appSecret = null;
    public function __construct()
    {
        $client = new Client();
        $this->client = $client;
        $this->appId = config('wechat.app_id');
        $this->appSecret = config('wechat.app_secret');
    }

    public function getAccessToken()
    {
        $accessTokenKey = 'wechat:access:key';
        $cache = Cache::get($accessTokenKey);
        if($cache) {
            return $cache;
        }
        $url = 'https://api.weixin.qq.com/cgi-bin/stable_token';
        $formParams = [
            'appid' => $this->appId,
            'secret' => $this->appSecret,
            'grant_type' => 'client_credential'
        ];
        try {
            $options = [
                'json' => $formParams,
                'headers' => [
                    'Content-Type' => 'application/json'
                ]
            ];
            $response = $this->client->request('POST', $url, $options);
            // 获取响应体并解码为数组
            $body = json_decode($response->getBody()->getContents(), true);
            if (!empty($body['errcode'])) {
                $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg']));
            } else {
                Cache::put($accessTokenKey, $body['access_token'], 240);
                return $body['access_token'];
            }
        } catch (RequestException $e) {
            $this->throwApiError($options, $e->getMessage(), $e->getCode());
        }
    }

    public function getSessionInfo($code)
    {
        $url = 'https://api.weixin.qq.com/sns/jscode2session';
        // 准备请求参数
        $formParams = [
            'appid' => $this->appId,
            'secret' => $this->appSecret,
            'js_code' => $code,
            'grant_type' => 'authorization_code'
        ];
        try {
            $options = [
                'query' => $formParams
            ];
            $response = $this->client->request('GET', $url, $options);
            // 获取响应体并解码为数组
            $body = json_decode($response->getBody()->getContents(), true);
            if (!empty($body['errcode'])) {
                $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg']));
            } else {
                // $openid = $data['openid'];
                // $sessionKey = $data['session_key'];
                return $body;
            }
        } catch (RequestException $e) {
            $this->throwApiError($options, $e->getMessage(), $e->getCode());
        }
    }

    public function getUserPhoneNumber($code)
    {
        $url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber';
        // 准备请求参数
        try {
            $options = [
                'query' => ['access_token' => $this->getAccessToken()],
                'json' => ['code' => $code],
                'headers' => [
                    'Content-Type' => 'application/json'
                ]
            ];
            $response = $this->client->request('POST', $url, $options);
            // 获取响应体并解码为数组
            $body = json_decode($response->getBody()->getContents(), true);
            if (!empty($body['errcode'])) {
                $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg']));
            } else {
                /*
                 * {
                    "errcode":0,
                    "errmsg":"ok",
                    "phone_info": {
                        "phoneNumber":"xxxxxx",
                        "purePhoneNumber": "xxxxxx",
                        "countryCode": 86,
                        "watermark": {
                            "timestamp": 1637744274,
                            "appid": "xxxx"
                        }
                    }
                   }
                 */
                return $body;
            }
        } catch (RequestException $e) {
            $this->throwApiError($options, $e->getMessage(), $e->getCode());
        }
    }

    public function getWxaQueryScheme($scheme)
    {
        //https://api.weixin.qq.com/wxa/queryscheme?access_token=ACCESS_TOKEN
        //query_type
        $keyScheme = 'key:wechat:key:scheme';
        $cache = Cache::get($keyScheme);
        if($cache) {
            return $cache;
        }
        $url = 'https://api.weixin.qq.com/wxa/generatescheme';
        // 准备请求参数
        try {
            $options = [
                'query' => ['access_token' => $this->getAccessToken()],
                'json' => ['expire_time' => strtotime('+28 day', time()), 'expire_type' => 0],
                'headers' => [
                    'Content-Type' => 'application/json'
                ]
            ];
            $response = $this->client->request('POST', $url, $options);
            // 获取响应体并解码为数组
            $body = json_decode($response->getBody()->getContents(), true);
            if (!empty($body['errcode'])) {
                $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg']));
            } else {
                Cache::put($keyScheme, $body['openlink'], 20 * 24 * 60 * 60);
                return $body['openlink'] ?? '';
            }
        } catch (RequestException $e) {
            $this->throwApiError($options, $e->getMessage(), $e->getCode());
        }
    }

    public function decryptData(string $sessionKey, string $iv, string $encrypted)
    {
        $decrypted = AES::decrypt(
            base64_decode($encrypted, false), base64_decode($sessionKey, false), base64_decode($iv, false)
        );

        $decrypted = json_decode($this->pkcs7Unpad($decrypted), true);

        if (!$decrypted) {
            $this->throwApiError([$sessionKey, $iv, $encrypted], '解密失败', 500);
        }

        return $decrypted;
    }

    public function pkcs7Unpad(string $text)
    {
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }

        return substr($text, 0, (strlen($text) - $pad));
    }

    private function throwApiError($options, $error, $code = 200)
    {
        $key = createGuid();
        Log::info('Wechat第三方接口出错key：'.$key);
        Log::info('Wechat第三方接口出错params：'.json_encode($options));
        Log::info('Wechat第三方接口出错：'.$code.'，'.$error);
        throw new ApiException(500);
    }
}
