<?php
namespace App\Helper;
use App\Helper\UniPlatform\BaseAPI;
use App\Helper\UniPlatform\BaseUniPlatform;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

/**
 * Class Kuaishou
 *
 * @package App\Helper
 * @property-read  string $appId
 * @property-read  string $slat
 * @property-read  string $secret
 * @property-read  string $token
 * @property-read  string $accessTokenFile
 * @property-read  string $accessToken
 * @property-read  string $noticeUrl
 * @property-read  string $validTimestamp
 */
class Kuaishou extends BaseUniPlatform
{
    public function __construct(BaseAPI $api)
    {
        $this->API  = $api;
    }

    /**
     * @param string $code
     * @return array|mixed
     * @throws \Exception
     */
    public function login($code = ''): array
    {
        return $this->post($this->API::LOGIN, [
            'app_id'       => $this->appId,
            'app_secret'   => $this->secret,
            'js_code'      => $code,
        ]);
    }


    public function createOrder($outOrderNo, $totalAmount, $openId): array
    {
        $data = [
            'app_id'        => $this->appId,
            'out_order_no'  => $outOrderNo,
            'open_id'       => $openId,
            'total_amount'  => intval($totalAmount * 100),
            'subject'       => "订单号：".$outOrderNo,
            'detail'        => '快手担保支付',
            'type'          => 1233, // @url https://mp.kuaishou.com/docs/operate/platformAgreement/epayServiceCharge.html
            'expire_time'   => $this->validTimestamp,
            'notify_url'    => $this->noticeUrl
        ];
        $data['sign'] = $this->getSign($data);
        $url = $this->API::CREATE_ORDER.'?'.http_build_query([
                'app_id' => $this->appId,
                'access_token' =>  $this->accessToken,
            ]);
        $res  = $this->post(
            $url,
            $data,
            'json'
        );

        return  [
            'order_id' => $res['order_info']['order_no'],
            'order_token' => $res['order_info']['order_info_token']
        ];
    }


    /**
     * @param array  $data
     * @return string
     */
    public function getSign(array $data)
    {
        $filterArray = ['sign','access_token'];
        $rList = array();
        foreach ($data as $k => $v) {
            if (in_array($k, $filterArray))
                continue;
            $value = trim(strval($v));
            $len = strlen($value);
            if ($len > 1 && substr($value, 0, 1) == "\"" && substr($value, $len, $len - 1) == "\"")
                $value = substr($value, 1, $len - 1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            array_push($rList, "$k=$value");
        }
        sort($rList, SORT_STRING);
        $str = implode('&', $rList);
        $str .= $this->secret;
        return md5($str);
    }


    protected function getAccessToken(): string
    {
        $res = $this->post($this->API::ACCESS_TOKEN, [
            'app_id'      => $this->appId,
            'app_secret'  => $this->secret,
            'grant_type'  => 'client_credentials',
        ]);
        if (!isset($res['result']) || $res['result'] != 1) {
            throw new \Exception('获取access token 错误');
        }

        file_put_contents($this->accessTokenFile, json_encode([
            'access_token' => $res['access_token'],
            'expires_at'   => Carbon::now()->timestamp + $res['expires_in']
        ]));

        return $res['access_token'];
    }

    protected function setAccessFileDir(): void
    {
        $this->accessTokenDir = storage_path('app/kuaishou');
    }

    protected function setAccessFilePath(): void
    {
        $this->accessTokenFile = storage_path('app/kuaishou/kuaishou_access_token.json');
    }


    public function getNotifySign(array $data)
    {
        $req = file_get_contents('php://input');
        $str = $req.$this->secret;
        return md5($str);
    }

    /**
     * @param string $uri
     * @param array  $data
     * @param string $type
     * @return array
     * @throws \Exception
     */
    protected function post($uri = '', $data = [], $type = 'urlencoded'): array
    {
        try {
            $client = new Client();
            if($type == 'urlencoded'){
                $url = $uri.'?'.http_build_query($data);
                $options = [
                    'verify'  => false,
                    'headers' => ['Content-Type' => 'x-www-form-urlencoded'],
                ];
            }else{
                $url = $uri;
                $options = [
                    'verify'  => false,
                    'headers' => ['Content-Type' => 'application/json'],
                    'body' => json_encode($data)
                ];
            }
            $res = $client->post($url, $options);
            $stringBody = (string)$res->getBody();
            $res = json_decode($stringBody, true);

            if(!isset($res['result']) || $res['result'] != 1){
                throw new \Exception("请求快手API接口错误，错误码:{$res['result']}，错误信息:{$res['error_msg']}");
            }
            return $res;
        } catch (GuzzleException $e) {
            \Log::error($e->getMessage());
            throw new \Exception($e->getMessage());
        }
    }

    protected function setNoticeUrl(): void
    {
        $this->noticeUrl = env('APP_URL').'/api/pay/kuaishou/notify';
    }

}
