<?php


namespace App\Traits;

use App\Exceptions\TencentImAccountException;
use App\Exceptions\TencentImException;
use App\Services\RedisService;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
use Tencent\TLSSigAPIv2;

trait TencentIm
{
    protected $restApiName;
    protected $identifier;
    protected $TENCENT_IM_USER_SIG_EXPIRE = 86400 * 180; //签名过期时间，单位秒，默认 180 天（同步SDK）
    protected $TENCENT_IM_BASE_API_HOST = 'https://console.tim.qq.com/'; //基础请求接口域名
    protected $REST_APT_MAX_ITEM = 100;

    /**
     * 验证是否配置完善
     * @return bool
     * @throws TencentImException
     */
    static public function verifyConfig()
    {
        if (!config('im.sdk_app_id') || !config('im.identifier') || !config('im.secret_key')) {
            throw new TencentImException('未配置完善,请检查!');
        }
        return true;
    }

    /**
     * 获取配置
     * @return array
     * @throws TencentImException
     */
    static public function getTencentImConfig()
    {
        self::verifyConfig();
        return [
            'sdk_app_id' => config('im.sdk_app_id'),
            'secret_key' => config('im.secret_key'),
            'identifier' => config('im.identifier')
        ];
    }

    /**
     * 获取签名
     * @param string $identifier
     * @return string
     * @throws TencentImException
     */
    public function getUserSig(string $identifier): string
    {
        if (RedisService::redis()->exists('tencentIm:userSign:' . $identifier)) {
            return RedisService::redis()->get('tencentIm:userSign:' . $identifier);
        }

        $userSig = $this->generateUserSig($identifier);

        RedisService::redis()->SETEX('tencentIm:userSign:' . $identifier, $this->TENCENT_IM_USER_SIG_EXPIRE - 10, $userSig);

        return $userSig;

    }

    /**
     * 生成签名
     * @param string $identifier
     * @param float|int $expire
     * @return string
     * @throws TencentImException
     */
    public function generateUserSig(string $identifier, $expire = null)
    {
        $imConfig = self::getTencentImConfig();
        $tlsApi = new TLSSigAPIv2(Arr::get($imConfig, 'sdk_app_id'), Arr::get($imConfig, 'secret_key'));
        $userSig = $tlsApi->genSig($identifier, $expire ?? $this->TENCENT_IM_USER_SIG_EXPIRE);
        return $userSig;
    }

    /**
     * 获取IM接口请求公共参数
     * @return string
     * @throws TencentImException
     */
    public function generateTencentImRestApiPublicParams()
    {
        self::verifyConfig();

        $params = [
            'sdkappid' => config('im.sdk_app_id'),
            'identifier' => config('im.identifier'),
            'usersig' => $this->getUserSig(config('im.identifier')),
            'random' => rand(10000, 4294967295),
            'contenttype' => 'json'
        ];

        return http_build_query($params);
    }

    /**
     * 获取腾讯IM RESTAPI 基础 HOST
     * @return string
     * @throws TencentImException
     */
    public function getTencentImRestApiBaseHost()
    {
        if (is_null($this->restApiName)) {
            throw new TencentImException('未设置请求接口');
        }
        return $this->TENCENT_IM_BASE_API_HOST . $this->restApiName . '?' . $this->generateTencentImRestApiPublicParams();
    }

    /**
     * 检测单次api请求是否超过上限
     * @param array $accounts
     * @return bool
     * @throws TencentImAccountException
     */
    public function verifyRestApiMaxItem(array $accounts)
    {
        if (count($accounts) > $this->REST_APT_MAX_ITEM) {
            throw new TencentImAccountException('单次最多处理100个用户名');
        }
        return true;
    }

    /**
     * 请求接口
     * @param string $requestUrl
     * @param array $apiData
     * @param string $method
     * @param string $paramsType
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function requestApi(string $requestUrl, array $apiData, string $paramsType = 'json', string $method = 'POST')
    {

        $client = new Client();
        if ($paramsType === 'json') {
            $apiData = json_encode($apiData);
        }
        $response = $client->request($method, $requestUrl, [
            'headers' => ['Accept' => 'multipart/json'],
            'body' => $apiData,
        ]);
        $result = json_decode($response->getBody(), true);
        return $result;
    }

    /**
     * 验证接口返回
     * @param $apiResult
     * @return bool
     * @throws TencentImException
     */
    static public function verifyApiResult($apiResult)
    {
        if (!is_array($apiResult)) {
            throw new TencentImException('IM 请求失败');
        }
        if (count(array_diff(['ActionStatus', 'ErrorCode', 'ErrorInfo'], array_keys($apiResult))) > 0) {
            throw new TencentImException('IM 接口返回异常');
        }
        if (($apiResult['ActionStatus'] != 'OK') || ($apiResult['ErrorCode'] != 0)) {
            throw new TencentImException('操作失败:   ' . $apiResult['ErrorInfo']);
        }
        return true;
    }


}
