<?php
/**
 * Created by PhpStorm.
 * User: tandunzhao
 * Date: 2017/12/4
 * Time: 上午11:49
 */

namespace App\Modules\Book\Services;

use Redis;
use EasyWeChat\Foundation\Application;

class ChapterShareWechatConfigService
{
    private $appId;

    private $appSecret;


    public function __construct($appId,$appSecret)
    {
        $this->appId = $appId ? $appId : env('JS_AppID');
        $this->appSecret = $appSecret ? $appSecret : env('JS_AppSecret');
        //\Log::info('appId:'.($this->appId).'appSecret:'.($this->appSecret));
    }

    public function getSignPackage($url='',$is_force = true , $only_cache= false)
    {
        $jsapiTicket = $this->getJsApiTicket($is_force , $only_cache );
        $protocol = (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = $url?$url:"$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
        \Log::info($string);
        $signature = sha1($string);

        $signPackage = array(
            "appId" => $this->appId,
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }

    private function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i ++)
        {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    private function getJsApiTicket($is_force = false , $only_cache= true )
    {
        // jsapi_ticket 应该全局存储与更新，以下代码以写入到文件中做示例
        $data = unserialize(Redis::get(($this->appId)."jsapi_ticket"));
        if (empty($data) || $data['expire_time'] < time())
        {

            $accessToken = $this->getToken($is_force, $only_cache);

            \Log::info(($this->appId).':'.$accessToken);
            // 如果是企业号用以下 URL 获取 ticket
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$accessToken}";
            $res = json_decode($this->httpGet($url));
            $ticket = $res->ticket;
            if ($ticket)
            {
                $data['expire_time'] = time() + 7000;
                $data['jsapi_ticket'] = $ticket;

                Redis::setex(($this->appId)."jsapi_ticket", 7000, serialize($data));
            }
        } else
        {
            $ticket = $data['jsapi_ticket'];
        }
        \Log::info(($this->appId).':'.'jsapi_tiket:'.$ticket);
        return $ticket;
    }

    private function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 3);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }

    /**
     * 获取access token
     *
     * @param string $is_force
     * @return unknown|unknown|mixed|object|boolean
     */
    public function getToken($is_force = true , $only_cache= true )
    {
        if ($is_force == false)
        {
            $data = unserialize(Redis::get(($this->appId)."access_token"));
            if ($data)
            {
                if (is_array($data) && $data['expire_time'] > time())
                {
                    $access_token = $data['access_token'];
                    return $access_token;
                } else if (is_string($data))
                {
                    $access_token = $data;
                    return $access_token;
                }
            }

            if( $only_cache ){
                // 非强制获取access_token，cache没有就直接返回false，防止获取access_token的接口在高并发下被滥用
                return false;
            }
        }

        $appId = $this->appId;
        $appSecret = $this->appSecret;
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appId . '&secret=' . $appSecret;
        $rs1 = self::https_request($url);
        \Log::info(($this->appId).'get_token-'.$rs1);
        if ($rs1)
        {
            $rs = json_decode($rs1, true);
            if (is_array($rs) && $rs['access_token'])
            {
                $access_token = $rs['access_token'];
                $expires_in = intval($rs['expires_in'], 10);
                if ($expires_in <= 0)
                {
                    $expires_in = 5;
                } else if ($expires_in >= 7200)
                {
                    $expires_in = 7000;
                }

                $data = array();
                $data['expire_time'] = time() + $expires_in;
                $data['access_token'] = $access_token;

                Redis::setex(($this->appId).'access_token', $expires_in, serialize($data));
                return $access_token;
            } else
            {
                $content = "get access token error:" . $rs1;
                \Log::info(($this->appId).$content);
            }
        } else
        {
            $content = "get access token error:" . $rs1;
            \Log::info(($this->appId).$content);
        }

        return false;
    }

    /**
     * 抓https数据
     *
     * @param unknown $url
     * @param string $data
     * @param string $timeout
     */
    static function https_request($url, $data = null, $timeout = 5000)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (! empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        if ($timeout) {
            curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
        }

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        if ($output === false) {
            \Log::error('Curl error: ' . curl_error($curl).". url:".$url);
        }

        curl_close($curl);
        return $output;
    }

    public static function getConfig($url){
        $options = [
            'debug'  => false,
            'app_id' => env('JS_AppId'),
            'secret' => env('JS_AppSecret'),
            //'token'  => 'easywechat',

            // 'aes_key' => null, // 可选

            'log' => [
                'level' => 'debug',
                'file'  => storage_path('easywechat.log'), // XXX: 绝对路径！！！！
            ],

        ];
        $app = new Application($options);
        $js = $app->js;
        $js->setUrl($url);
        $config =$js ->Config([
            'onMenuShareTimeline',
            'onMenuShareAppMessage',
            'onMenuShareQQ',
            'onMenuShareWeibo',
            'showOptionMenu',
            'hideOptionMenu',
            'hideMenuItems',
            'hideAllNonBaseMenuItem'
        ],$debug = false, $beta = false, $json = false);
        return $config;
    }
}