<?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.
 *
 * @property string $appId
 * @property string $slat
 * @property string $secret
 * @property string $token
 * @property string $accessTokenFile
 * @property string $accessToken
 * @property string $noticeUrl
 * @property 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'],
        ];
    }

    public function settle($orderNo, $amount)
    {
        $url = $this->API::SETTLE . '?' . http_build_query([
            'app_id'       => $this->appId,
            'access_token' => $this->accessToken,
        ]);
        $data = [
            'app_id'        => $this->appId,
            'out_order_no'  => $orderNo,
            'out_settle_no' => $orderNo,
            'reason'        => '主动结算',
            'notify_url'    => env('APP_URL') . '/api/pay/kuaishou/settle',
            'settle_amount' => $amount,
        ];
        $data['sign'] = $this->getSign($data);

        return $this->post(
            $url,
            $data,
            'json'
        );
    }

    public function pushOrder($openid, $orderId, $createAt): array
    {
        $data = [
            'app_id'               => $this->appId,
            'out_order_no'         => $orderId,
            'out_biz_order_no'     => $orderId,
            'open_id'              => $openid,
            'order_create_time'    => (int) Carbon::parse($createAt)->getPreciseTimestamp(3),
            'order_status'         => 11, // 支付成功 虚拟
            'order_path'           => 'pages/my/consume',
            'product_cover_img_id' => '5acfa29b90c8234ff41ede600cad6a9b715f38871eaf5973',
        ];
        $url = $this->API::ORDER_PUSH . '?' . http_build_query([
            'app_id'       => $this->appId,
            'access_token' => $this->accessToken,
        ]);

        return $this->post($url, $data, 'json');
    }

    public function upload()
    {
        $url = 'https://open.kuaishou.com/openapi/mp/developer/file/img/uploadWithUrl?' . http_build_query([
            'app_id'       => $this->appId,
            'access_token' => $this->accessToken,
            'url'          => 'http://fourtiao.oss-cn-beijing.aliyuncs.com/zhangsiye/images/664b34c5afb8cb56d4a3cec398e64948.png',
        ]);

        return $this->post(
            $url,
        );
    }

    /**
     * @return string
     */
    public function getSign(array $data)
    {
        $filterArray = ['sign', 'access_token'];
        $rList       = [];
        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 || 'null' == $value) {
                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']) || 1 != $res['result']) {
            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
     *
     * @throws \Exception
     */
    protected function post($uri = '', $data = [], $type = 'urlencoded'): array
    {
        try {
            $client = new Client();
            if ('urlencoded' == $type) {
                $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']) || 1 != $res['result']) {
                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';
    }
}
