<?php


namespace App\Libs\Push\VPush;


use App\Libs\Utils;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

/**
 * Vivo推送
 * 服务端接口文档地址：https://dev.vivo.com.cn/documentCenter/doc/362
 * Class VPush
 * @package App\Libs\Push\VPush
 */
class VPush
{
    // App基本配置
    private $_appId;
    private $_appKey;
    private $_appSecret;

    // 授权token
    private $_accessToken = '';

    // 推送内容及推送用户
    private $_title = '';
    private $_content = '';
    private $_skipContent = '';
    private $_regId = [];

    // 消息体的id
    private $_taskId = '';

    // 推送设置
    private $_notifyType = 4;
    private $_timeToLive = 86400;
    private $_skipType = 4;
    private $_networkType = -1;

    public function __construct($appId, $appKey, $appSecret)
    {
        $this->_appId     = $appId;
        $this->_appKey    = $appKey;
        $this->_appSecret = $appSecret;
    }

    /**
     * 设置推送消息
     * @param       $title
     * @param       $content
     * @param       $url
     * @param array $regId
     */
    public function setPushData($title, $content, $url, $regId = [])
    {
        // 赋值
        $this->_title       = $title;
        $this->_content     = $content;
        $this->_skipContent = $url;
        $this->_regId       = $regId;
    }

    /**
     * 保存群推消息公共体接口
     * @return mixed
     * @throws GuzzleException
     * @throws Exception
     */
    public function saveListPayload()
    {
        // 校验参数
        $this->checkParam();
        $data = [
            'requestId'       => Utils::randCode(),
            'title'           => $this->_title,
            'content'         => $this->_content,
            'notifyType'      => $this->_notifyType,
            'timeToLive'      => $this->_timeToLive,
            'skipType'        => $this->_skipType,
            'skipContent'     => $this->_skipContent,
            'networkType'     => $this->_networkType,
            'clientCustomMap' => (object)[],
        ];

        // 请求服务接口
        $result        = $this->getData(config('push.server.vivo.saveListPayload'), $data);
        $this->_taskId = getProp($result, 'taskId');
        return $result;
    }

    /**
     * 批量推送用户接口
     * @return mixed
     * @throws GuzzleException
     */
    public function sendMessage()
    {
        // 参数判断
        $this->checkParam();
        if (!$this->_taskId) {
            throw new Exception('VIVO推送必须要设置taskId');
        }
        if (!$this->_regId) {
            throw new Exception('VIVO推送必须要设置regId');
        }

        $data = [
            'regIds'    => $this->_regId,
            'taskId'    => $this->_taskId,
            'requestId' => Utils::randCode(),
        ];

        return $this->getData(config('push.server.vivo.pushToList'), $data);
    }

    /**
     * 单个用户发送
     * @return mixed
     * @throws GuzzleException
     */
    public function send(string $regId,string $title, string $content, string $url)
    {
        // 校验参数
        $data = [
            'regId' => $regId,
            'requestId'       => Utils::randCode(),
            'title'           => $title,
            'content'         => $content,
            'notifyType'      => $this->_notifyType,
            'timeToLive'      => $this->_timeToLive,
            'skipType'        => $this->_skipType,
            'skipContent'     => $url,
            'networkType'     => $this->_networkType,
            'clientCustomMap' => (object)[],
        ];

        return $this->getData(config('push.server.vivo.sendMessage'), $data);
    }

    /**
     * 全量发送（默认是每个app每日可发送一条。）
     * @return mixed
     * @throws GuzzleException
     */
    public function sendAll()
    {
        // 校验参数
        $this->checkParam();
        $data = [
            'requestId'       => Utils::randCode(),
            'title'           => $this->_title,
            'content'         => $this->_content,
            'notifyType'      => $this->_notifyType,
            'timeToLive'      => $this->_timeToLive,
            'skipType'        => $this->_skipType,
            'skipContent'     => $this->_skipContent,
            'networkType'     => $this->_networkType,
            'clientCustomMap' => (object)[],
        ];

        return $this->getData(config('push.server.vivo.sendAll'), $data);
    }

    /**
     * 标签推
     * @param $tag
     * @return mixed
     * @throws GuzzleException
     */
    public function tagPush($tag)
    {
        // 校验参数
        $this->checkParam();
        $data = [
            'requestId'       => Utils::randCode(),
            'title'           => $this->_title,
            'content'         => $this->_content,
            'notifyType'      => $this->_notifyType,
            'timeToLive'      => $this->_timeToLive,
            'skipType'        => $this->_skipType,
            'skipContent'     => $this->_skipContent,
            'networkType'     => $this->_networkType,
            'clientCustomMap' => (object)[],
            'tagExpression'   => [
                'andTags' => [],
                'notTags' => [],
                'orTags'  => [$tag]
            ]
        ];

        return $this->getData(config('push.server.vivo.tagPush'), $data, 'POST');
    }

    /**
     * 新增标签
     * @param $tag
     * @return false|mixed
     * @throws GuzzleException
     */
    public function addTag($tag)
    {
        if (empty($tag)) {
            return false;
        }

        // token授权
        $this->getAccessToken();

        // 拼接链接
        $url = config('push.server.vivo.addTag');

        return $this->getData($url, [
            'name' => $tag
        ], 'POST');
    }

    /**
     * 给用户绑定tag
     * @param $tag
     * @param $regIds
     * @return false|mixed
     * @throws GuzzleException
     */
    public function addTagForUsers($tag, $regIds)
    {
        if (empty($tag) || empty($regIds)) {
            return false;
        }

        // token授权
        $this->getAccessToken();

        // 拼接链接
        $url = config('push.server.vivo.addMembers');

        return $this->getData($url, [
            'name' => $tag,
            'type' => 1,
            'ids'  => $regIds
        ], 'POST');
    }

    /**
     * 获取消息推送的统计值接口
     * @param $taskIds
     * @return array|mixed
     * @throws GuzzleException
     */
    public function getStatistics($taskIds)
    {
        if (empty($taskIds)) {
            return [];
        }

        // token授权
        $this->getAccessToken();

        // 拼接链接
        $url = config('push.server.vivo.getStatistics');
        $url .= '?taskIds=' . implode(',', $taskIds);

        return $this->getData($url, [], 'GET');
    }

    /**
     * 校验参数
     * @return $this
     * @throws GuzzleException
     */
    private function checkParam()
    {
        // 授权token校验
        if (!$this->_accessToken) {
            $this->getAccessToken();
        }

        if (!$this->_appId) {
            throw new Exception('VIVO推送必须要设置appId');
        }
        if (!$this->_appKey) {
            throw new Exception('VIVO推送必须要设置appKey');
        }
        if (!$this->_appSecret) {
            throw new Exception('VIVO推送必须要设置appSecret');
        }
        if (!$this->_accessToken) {
            throw new Exception('VIVO推送必须要设置AccessToken');
        }
        if (!$this->_title) {
            throw new Exception('VIVO推送必须要设置title');
        }
        if (!$this->_content) {
            throw new Exception('VIVO推送必须要设置content');
        }
        if (!$this->_timeToLive) {
            throw new Exception('VIVO推送必须要设置timeToLive');
        }
        return $this;
    }

    /**
     * 授权
     * @return $this
     * @throws GuzzleException
     */
    private function getAccessToken()
    {
        $sendData           = [
            'appId'     => $this->_appId,
            'appKey'    => $this->_appKey,
            'timestamp' => time() . '000',
        ];
        $sign               = md5($sendData['appId'] . $sendData['appKey'] . $sendData['timestamp'] . $this->_appSecret);
        $sendData['sign']   = $sign;
        $url                = config('push.server.vivo.auth');
        $data               = $this->getData($url, $sendData);
        $this->_accessToken = getProp($data, 'authToken');

        return $this;
    }

    /**
     * 请求数据
     * @param        $url
     * @param        $sendData
     * @param string $method
     * @return mixed
     * @throws GuzzleException
     */
    private function getData($url, $sendData, $method = 'POST')
    {
        // 组装请求数据
        $authToken = $this->_accessToken;
        $option    = ['json' => $sendData];

        // 请求
        $client = new Client(['timeout' => 5.0, 'headers' => ['authToken' => $authToken]]);
        if ($method === 'POST') {
            $response = $client->request('POST', $url, $option);
        } else {
            $response = $client->request('GET', $url);
        }

        $body   = $response->getBody()->__toString();
        $result = json_decode($body, true);

        myLog('push')->info('[VIVO] getDataByInfo', compact('url', 'option', 'authToken', 'result'));
        return $result;
    }
}

